Объектно-ориентированный подход. Объектно_ориентированный_подход. Объектно ориентированный подход Мэтт Вайсфельд 5е международное издание ббк 32. 973. 2018
Скачать 5.43 Mb.
|
115 Проектирование.с.учетом.расширяемости. . ПРАВИЛЬНОЕ СОГЛАШЕНИЕ ОБ ИМЕНОВАНИИ _______________________________________ Убедитесь.в.том,.что.соглашение.об.именовании.имеет.смысл..Люди.часто.пере- барщивают.и.придумывают.соглашения,.которые.имеют.смысл.для.них,.но.оказы- ваются.совершенно.непонятными.для.других.людей..Будьте.осторожны,.вынуждая. других.следовать.тому.или.иному.соглашению..Удостоверьтесь.в.том,.что.соглашения. разумны.и.всем.заинтересованным.людям.понятен.смысл,.который.в.них.кроется.. Название.переменных.должно.отражать.их.роль,.а.не.их.тип. Абстрагирование непереносимого кода Если вы проектируете систему, которая должна задействовать непереносимый (нативный) код (то есть код, который будет выполняться только на определенной аппаратной платформе), то вам придется абстрагировать его от соответствующего класса. Под абстрагированием мы подразумеваем изоляцию непереносимого кода в его собственном классе или по крайней мере в его собственном методе (который может быть переопределен). Например, если вы пишете код для доступа к после- довательному порту определенного аппаратного обеспечения, то вам следует создать класс-обертку для работы с ним. Ваш класс затем должен будет отправить сообщение классу-обертке для получения информации и услуг, которые ему нуж- ны. Не размещайте зависимый от системы код в своем первичном классе (рис. 5.5). Рис. 5.5. Обертка.для.работы.с.последовательным.портом Рассмотрим, например, ситуацию, когда программист взаимодействует непосред- ственно с аппаратным обеспечением. В таких случаях объектный код разных платформ, скорее всего, будет сильно отличаться, поэтому код потребуется на- писать для каждой платформы. Однако если функциональность будет заключена в класс-обертку, то пользователь класса сможет взаимодействовать непосредствен- но с оберткой и ему не придется беспокоиться о различном низкоуровневом коде. Класс-обертка разберется в различиях платформ и решит, какой код вызывать. Глава.5..Руководство.по.проектированию.классов 116 Обеспечение возможности осуществлять копирование и сравнение В главе 3 мы говорили о копировании и сравнении объектов. Важно понимать, как осуществляются эти действия. Вы, возможно, не захотите или не будете рассчитывать на простую побитовую копию или операцию сравнения. Вы долж- ны убедиться в том, что ваш класс ведет себя так, как от него ожидается, а это означает, что вам придется потратить некоторое время на проектирование спо- собов копирования и сравнения объектов. Сведение области видимости к минимуму Сведение области видимости к минимуму идет рука об руку с абстрагировани- ем и сокрытием реализации. Идея заключается в том, чтобы локализовать атрибуты и поведения настолько, насколько это представляется возможным. Таким образом, сопровождать, тестировать и расширять классы станет намного легче. Применение интерфейсов хорошо помогает это обеспечить. ОБЛАСТЬ ВИДИМОСТИ И ГЛОБАЛЬНЫЕ ДАННЫЕ _____________________________________ Минимизация. области. видимости. глобальных. переменных. —. хороший. стиль. .программирования,.но.она.характерна.не.только.для.объектно-ориентированного. программирования..При.структурной.разработке.допускается.использование.гло- бальных.переменных,.однако.это.рискованно..Фактически.в.сфере.объектно-ори- ентированной.разработки.нет.глобальных.данных..Статические.атрибуты.и.методы. совместно.используются.объектами.одного.и.того.же.класса,.однако.они.недоступ- ны.остальным.объектам..Вы.также.можете.обеспечить.общий.доступ.к.данным.через. файл.или.базу.данных. Например, если у вас имеется метод, которому требуется временный атрибут, пусть он будет локальным. Взгляните на приведенный далее код: public class Math { int temp=0; public int swap (int a, int b) { temp = a; a=b; b=temp; return temp; } } 117 Проектирование.с.учетом.сопровождаемости. . Что не так с этим классом? Проблема заключается в том, что необходимо, чтобы атрибут temp был только в рамках области видимости метода swap() . Нет ника- ких причин для того, чтобы он был на уровне класса. Таким образом, вам сле- дует переместить temp в область видимости метода swap() : public class Math { public int swap (int a, int b) { int temp=0; temp = a; a=b; b=temp; return temp; } } Вот что подразумевается под сведением области видимости к минимуму. Проектирование с учетом сопровождаемости Проектирование практичных и компактных классов обеспечивает высокий уро- вень сопровождаемости. Точно так же как вы проектируете классы с учетом рас- ширяемости, вам следует проектировать их с учетом будущего сопровождения. Процесс проектирования классов вынудит вас разделять ваш код на множество идеально управляемых фрагментов. Отдельные фрагменты кода гораздо удобнее в сопровождении, чем его более крупные фрагменты (по крайней мере так счи- тается). Один из наилучших способов обеспечить сопровождаемость — умень- шить количество взаимозависимого кода, то есть изменения в одном классе не должны сказываться, даже минимально, на других классах. ТЕСНО СВЯЗАННЫЕ КЛАССЫ __________________________________________________________ Классы,.которые.сильно.зависят.друг.от.друга,.считаются.тесно.связанными..Таким. образом,.если.изменение,.внесенное.в.один.класс,.приводит.к.изменению.в.другом. классе,.то.эти.два.класса.будут.считаться.тесно.связанными..Классы,.лишенные. таких.зависимостей,.обладают.очень.низкой.степенью.связанности..Более.подроб- но.об.этом.вы.сможете.узнать.из.книги.Скотта.Амблера.(Scott.Ambler).«Введение. в.объектно-ориентированную.технологию». Если классы изначально правильно спроектированы, то любые изменения в си- стеме должны вноситься только в реализацию объекта. Изменений открытого Глава.5..Руководство.по.проектированию.классов 118 интерфейса следует избегать любой ценой. Любые изменения открытого интер- фейса приведут к волновым эффектам во всех системах, задействующих этот интерфейс. Например, если внести изменение в метод getName() класса Cabbie , то все места во всех системах, где используется этот интерфейс, потребуется изменить и перекомпилировать. Обнаружение всех соответствующих вызовов методов — это грандиозная задача, а вероятность упустить один из них довольно высока. Для обеспечения высокого уровня сопровождаемости делайте так, чтобы степень связанности ваших классов была как можно ниже. Использование итерации в процессе разработки Как и в большинстве функций проектирования и программирования, рекомен- дуется использовать итеративный процесс. Это хорошо согласуется с концепци- ей обеспечения минимальных интерфейсов. По сути, это означает, что не нужно писать сразу весь код! Делайте это небольшими шагами, создавая и тестируя код на каждом этапе. Хороший план тестирования позволит быстро выявить все об- ласти, где обеспечены недостаточные интерфейсы. Таким образом, процесс мож- но будет повторять до тех пор, пока у класса не появятся надлежащие интерфей- сы. Этот процесс тестирования затрагивает не только написанный код. Очень полезно протестировать то, что вы спроектировали, с применением критического анализа и других методик оценки результатов. Использование итеративных про- цессов облегчает жизнь тестировщикам, поскольку они вовлекаются в ход со- бытий еще на раннем этапе, а не просто получают в свои руки систему, которую им «перебрасывают через стену» в конце процесса разработки. Тестирование интерфейса Минимальные реализации интерфейса часто называются заглушками (Гилберт и Маккарти хорошо рассмотрели тему заглушек в книге под названием «Объ- ектно-ориентированное проектирование на Java». Используя заглушки, вы сможете тестировать интерфейсы без написания реального кода. В приведенном далее примере вместо подключения к настоящей базе данных заглушки при- меняются для проверки того, что интерфейсы работают правильно (с точки зрения пользователя, ведь интерфейсы предназначены для них). Таким образом, на данном этапе нет необходимости в реализации. Более того, обеспечение за- вершенной реализации на данном этапе может стоить драгоценного времени и сил, поскольку конструкция интерфейса повлияет на реализацию, а интерфейс при этом еще не будет завершен. Обратите внимание на рис. 5.6: когда пользовательский класс отправляет со- общение классу DataBaseReader , информация, возвращаемая пользовательско- му классу, предоставляется кодовыми заглушками, а не настоящей базой данных 119 Проектирование.с.учетом.сопровождаемости. . (фактически базы данных, скорее всего, даже не существует). Когда интерфейс окажется завершен, а реализация будет находиться в процессе разработки, можно будет подключиться к базе данных, а заглушки — отключить. Рис. 5.6. Применение.заглушек Вот пример кода, который задействует внутренний массив для имитации рабо- тающей базы данных (хотя и простой): public class DataBaseReader { private String db[] = { "Record1","Record2","Record3","Record4", "Record5"}; private booleanDBOpen = false; private int pos; public void open(String Name){ DBOpen = true; } public void close(){ DBOpen = false; } public void goToFirst(){ pos = 0; } public void goToLast(){ pos = 4; Глава.5..Руководство.по.проектированию.классов 120 } public int howManyRecords(){ int numOfRecords = 5; return numOfRecords; } public String getRecord(int key){ /* DB Specific Implementation */ return db[key]; } public String getNextRecord(){ /* DB Specific Implementation */ return db[pos++]; } } Обратите внимание на то, как методы имитируют вызовы базы данных. Строки в массиве представляют записи, которые будут сохранены в базу данных. Когда база данных будет успешно интегрирована с системой, она станет использовать- ся вместо массива. СОХРАНЕНИЕ ЗАГЛУШЕК ______________________________________________________________ Когда.заглушки.сделают.свое.дело,.не.удаляйте.их..Сохраните.их.в.коде.для.воз- можного.применения.в.будущем.—.только.позаботьтесь.о.том,.чтобы.пользователи. не.смогли.увидеть.их,.а.члены.команды.программистов.знали.о.них..Фактически.в.той. или.иной.хорошо.спроектированной.программе,.которую.вы.тестируете,.заглушки. должны.быть.интегрированы.с.конструкцией.и.сохраняться.в.программе.для.после- дующего.использования..Коротко.говоря,.встраивайте.функциональность.для.осу- ществления.тестирования.прямо.в.класс!.Наверное,.даже.лучше.создавайте.заглуш- ки.с.мок-данными,.встроенные.в.интерфейсы,.тогда.вы.сможете.в.случае.надобности. убрать.их.из.самой.реализации. Сталкиваясь с проблемами при проектировании интерфейсов, вносите измене- ния и повторяйте процесс до тех пор, пока результат вас не устроит. Использование постоянства объектов Постоянство объектов — еще один вопрос, который требуется решать во многих объектно-ориентированных системах. Постоянство — это концепция сохране- ния состояния объекта. Если вы не сохраните объект тем или иным путем при выполнении программы, то он «умрет» и его нельзя будет «воскресить» когда- либо. Такие временные объекты могут работать в некоторых приложениях, однако в большинстве бизнес-систем состояние объекта должно сохраняться для последующего использования. 121 Использование.постоянства.объектов. . ПОСТОЯНСТВО ОБЪЕКТОВ _____________________________________________________________ Несмотря.на.то.что.тема.постоянства.объектов.может.и.не.показаться.действитель- но.относящейся.к.руководству.по.проектированию,.я.считаю,.что.обязательно.нуж- но.уделить.ей.внимание.при.проектировании.классов..Я.представляю.ее.здесь,. чтобы.подчеркнуть,.что.о.постоянстве.объектов.следует.подумать.еще.на.раннем. этапе.проектирования.классов. В своей простейшей форме объект может сохраняться, будучи сериализованным и записанным в простой файл. Самая современная технология сейчас базиру- ется на XML. Теоретически объект может сохраняться в памяти, пока не будет уничтожен, но мы сосредоточимся на сохранении постоянных объектов на чем- то вроде запоминающего устройства. Следует учитывать три типа первичных «запоминающих устройств». Система простых файлов — вы можете сохранить объект в простом файле, сериализовав его. Это определенно устаревший способ. Гораздо чаще объ- екты сериализуют в файлы XML и/или JSON и записывают в подобие фай- ловой системы, массива данных или конечного устройства. Их можно раз- местить в базе данных или записать на диск, что в наши дни является распространенной практикой. Реляционная база данных — для преобразования объекта в реляционную модель потребуется некоторое промежуточное программное обеспечение. Объектно-ориентированная база данных — может оказаться наиболее эф- фективным способом сделать объекты постоянными, однако вся информация большинства компаний содержится в унаследованных системах, и на данный момент маловероятно, что они решат преобразовать свои реляционные базы данных в объектно-ориентированные. Это наиболее распространенный тип баз данных с гибкой структурой. Самые известные — это MongoDB и Cos- mos DB. Сериализация и маршалинг объектов Мы уже рассматривали проблему использования объектов в средах, которые изначально предназначены для структурного программирования. Хороший образец — пример с промежуточным программным обеспечением, в котором мы записывали объекты в реляционную базу данных. Мы также затронули про- блему записи объекта в простой файл или передачи его по сети. Для передачи объекта по сети (например, файлу) система должна деконструи- ровать этот объект (сделать его простым), передать его по сети, а затем рекон- струировать на другом конце сети. Этот процесс называется сериализацией объекта. Действие по передаче объекта по сети называется маршалингом объ- екта. В теории сериализованный объект может быть записан в простой файл и извлечен позднее в том же состоянии, в каком был записан. Глава.5..Руководство.по.проектированию.классов 122 Основной вопрос здесь состоит в том, что при сериализации и десериализации должны использоваться одни и те же спецификации. Это что-то вроде алгорит- ма шифрования. Если один объект зашифрует строку, то другому объекту, ко- торый захочет расшифровать ее, придется использовать тот же алгоритм шиф- рования. В Java предусмотрен интерфейс Serializable , который обеспечивает соответствующее преобразование. Это еще одна причина, почему в наши дни данные отделены от поведений. Го- раздо проще создать интерфейс для контракта данных и разместить его на веб- сервисе, чем убедиться в том, что у обеих сторон одинаковый код. Резюме Эта глава содержит большое количество указаний, которые могут помочь вам в проектировании классов. Однако это ни в коей мере не исчерпывающий спи- сок. Вы, несомненно, узнаете и о других правилах, путешествуя по миру объ- ектно-ориентированного проектирования. В этой главе рассказано о решении задач проектирования касательно отдельных классов. Однако мы уже видели, что тот или иной класс не существует в изо- ляции. Классы призваны взаимодействовать с другими классами. Группа клас- сов, взаимодействующих друг с другом, представляет собой часть системы. В конечном счете именно такие системы ценны для конечных пользователей. В главе 6 мы рассмотрим тему проектирования полных систем. Ссылки Скотт Амблер, «Введение в объектно-ориентированную технологию» (The Object Primer). — 3-е изд. — Кембридж, Соединенное Королевство: Cambridge University Press, 2004. Стивен Гилберт и Билл Маккарти, «Объектно-ориентированное проектиро- вание на Java» (Object-Oriented Design in Java). — Беркли, штат Калифорния: The Waite Group Press (Pearson Education), 1998. Джейми Яворски, «Руководство разработчика на Java 1.1» (Java 1.1 Developers Guide). — Индианаполис, штат Индиана: Sams Publishing, 1997. Джейми Яворски, «Платформа Java 2 в действии» (Java 2 Platform Unleashed). — Индианаполис, штат Индиана: Sams Publishing, 1999. Скотт Майерс, «Эффективное использование C++» (Effective C++). — 3-е из- дание. — Бостон, штат Массачусетс: Addison-Wesley Professional, 2005. Пол Тима, Габриэл Торок и Трой Даунинг, «Учебник по Java для начинаю- щих» (Java Primer Plus). — Беркли, штат Калифорния: The Waite Group, 1996. Глава 6 ПРОЕКТИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ ОБЪЕКТОВ При использовании того или иного программного продукта вы ожидаете, что он будет функционировать так, как это заявлено. К сожалению, не все продукты оправдывают ожидания. Проблема заключается в том, что при создании боль- шого количества продуктов много времени и сил тратится на этапе программи- рования, а не на стадии проектирования. Объектно-ориентированное проектирование рекламировалось как надежный и гибкий подход к разработке программного обеспечения. По правде говоря, проектируя объектно-ориентированным способом, вы можете получить как хорошие, так и плохие результаты с той же легкостью, как и при использовании любого другого подхода. Пусть вашу бдительность не притупляет ложное чув- ство безопасности, основанное лишь на том, что вы применяете самую совре- менную методологию проектирования. Вы должны уделять внимание общей конструкции и тратить достаточное количество времени и сил на создание наилучшего продукта, который только возможен. В главе 5 мы сконцентрировались на проектировании хороших классов, а в этой главе сосредоточимся на проектировании хороших систем. Систему можно определить в виде классов, взаимодействующих друг с другом. Соответствующие методики проектирования развивались на протяжении всей истории разработ- ки программного обеспечения, и теперь вы можете смело пользоваться преиму- ществами того, что было достигнуто ценой крови, пота и слез ваших предше- ственников в сфере создания программного обеспечения, независимо от того, применяли они объектно-ориентированные технологии или нет. Во многих случаях вы просто будете брать код, который, возможно, нормально работает уже много лет, и буквально обертывать им свои объекты. Об обертывании мы поговорим позднее в этой главе. |