Философия Java


Проектировка - часть 3


Ключи для предположения по перепроектировке класса:

1) Запутанные операторы: подумайте о полиморфизме.

2) Большое число методов, которые обрабатывают различные типы или операции: подумайте о нескольких классах.

3) Большое число элементов переменных, которые относятся к различным характеристикам: подумайте о нескольких классах.

  • Следите за длинными списками аргументов. При этом вызовы, запись, чтение или обработка методов значительно затруднены. Вместо этого попробуйте переместить метод в класс, где его наиболее часто употребляют или передавайте ему объекты, как аргументы.
  • Не повторяйтесь. Если некий кусочек кода требуется в многих методах дочерних классов, то поместите его в один метод базового класса, а затем вызывайте его из дочернего. Это не только позволит сохранить место, но и позволит с легкостью вносить изменения. Иногда изучение этого общего кода приносит дополнительную функциональность вашему интерфейсу.
  • Следите за выражениями switch и цепочками if-else. Это всего лишь индикатор проверки кодирования, что означает, что Вы выбираете, какой код будет выполнен на основании некой информации (точный тип может быть не известен первоначально). Вы должны заменять этот код посредством наследования и полиморфизма; вызовы полиморфных методов выполняют за вас всю работу по проверке типов, что в результате позволяет иметь более гибкую систему.
  • С точки зрения проектировки, найдите и отделите те вещи, которые могут изменяться от тех, которые всегда постоянны. Это означает, что нужно в системе найти элементы, которые Вы можете изменить без принудительного редизайна, затем инкапсулируйте их в отдельные классы. Вы можете значительно больше узнать об этом в книге Thinking in Patterns with Java, доступной с www.BruceEckel.com.
  • Не расширяйте фундаментальную функциональность посредством подклассов. Если элемент интерфейса для класса важен, то он должен быть в базовом классе, а не добавлен в процессе наследования. Если же Вы добавляете методы во время наследования, то стоит подумать о перепроектировке.
  • Меньше - больше. Начинайте с минимума интерфейса класса, как можно меньшего, что бы только хватало решить поставленную задачу, не пытайтесь предугадать все варианты, как может быть использован ваш класс. Как только ваш класс будет использован, то здесь уже можно посмотреть и расширять его интерфейс. Но все равно, как только Вы "выпустите" класс, то уже будет невозможно раширять его интерфейс, без изменения его кода. Если вам нужно расширить интерфейс существующих методов, добавлением новых аргументов, создайте перегруженный метод с новыми аргументами.
  • "Прочтите" ваш класс в слух, что бы убедиться, что он логичен. Убедитесь, что отношения между базовым классом и дочерним классом есть "это - есть" ("is-a"), а у элементов класса "имеет это" ("has-a").
  • Во время принятия решения по использованию наследования или композиции, спросите себя, а нужно ли мне использовать приведение к базовому типу? Если нет, то предпочтите композицию наследованию. При этом отпадет необходимость в множестве базовых типов. Если же Вы наследуете, то пользователи могут не без оснований думать, что можно произвести приведение к базовому типу.
  • Используйте элементы данных для разнообразия в значениях, а переопределение методов для разнообразия в поведении. Это означает, что если Вы найдете класс, который использует значения переменных в месте с методами, для того, что бы изменять поведение в зависимости от значений этих переменных, то следует, скорее всего, перепроектировать этот класс. Нужно выразить различие в поведении в подклассы и переопределенные методы.
  • Следите за перегрузкой. Метод не должен выполняться на основе аргумента, вместо этого нужно создать два или более перегруженных методов.
  • Используйте иерархию исключений, желательно наследовать от специального класса в стандартной иерархии исключений Java. Если кто-то обрабатывает исключения, то он может обрабатывать только определенные типы исключений, следующие от этого базового класса. Если Вы добавляете новое дочернее исключение, то существующий клиентский код его все равно обработает, основываясь на базовом типе.
  • Иногда простая агрегация выполняют всю работу. "Система комфорта пассажира" на авиалиниях состоит из различных, отсоединенных друг от друга частей: сиденья, кондиционеры воздуха, видео и т.д., а теперь представьте, что вам нужно создать несколько таких систем в самолете. Вы сделаете частные (новые) элементы и создадите новый интерфейс? Нет, в этом случае, компоненты также являются частью публичного интерфейса, поэтому Вы должны просто создать публичные элементы-объекты. Эти объекты имеют свою собственную реализацию, но при этом они так же безопасны. Знайте, что простая агрегация не то решение, которое может часто применяться, но при его использовании все счастливы.
  • Примите во внимание клиентского программиста и того, кто будет обслуживать ваш код. Проектируйте ваш класс настолько ясно, насколько это возможно для использования. Предвидьте те изменения, которые могут с ним произойти и спроектируйте ваш класс так, что бы привнести их было в него просто.
  • Остерегайтесь синдрома гигантских объектов. Этот синдром - частое несчастье процедурных программистов, которые только начинают программировать в ООП, и кто еще не закончил писать процедурные программы и обычно помещает в своей объектной программе несколько больших объектов и все.
  • Если Вы должны сделать что-то ужасное, то меньшей мере сделайте это внутри класса.
  • Если вам нужно сделать что-то непереносимое, то создайте абстракцию и локализуйте ее в отдельном классе. Это уже более высокий уровень абстрагирования непереносимых элементов, которые будут распространяться с вашей системой. (Эта идиома материализована в шаблоне Bridge).
  • Объект должен не просто содержать данные. Они должны так же иметь и определенные принципы поведения. (Иногда, чистые объекты данных подходят, но только когда они используются для хранения или передачи группы элементов.)
  • Сперва используйте композицию, когда создаете новый класс от уже существующего. Вы должны использовать наследование только, если это требование вашего дизайна. Если Вы используете наследование, где должна быть использована композиция, то тогда ваш дизайн без нужды запутанный.
  • Используйте наследование и переопределение методов для выражения различий в поведении, а поля для выражения различий в положении. Крайним случаем того, чего не нужно делать - наследование различных классов для отображения цвета, вместо использования поля цвета.
  • Остерегайтесь конфликтов. Два семантически различных объектов могут иметь идентичные возможности по действиям или по ответственности, при этом возникает искушение попытаться создать один подкласс от этих классов посредством наследования. Отсюда и возникает конфликт, однако в этом случае нет необходимости оправдывающей создание связи дочернего класса с суперклассом. Поэтому лучшим решением будет создать главный базовый класс, который реализует интерфейс для обоих дочерних классов, при этом потребуется немного больше места, но у вас останутся все преимущества наследования.
  • Остерегайтесь ограничений наследования. В ясном дизайне новые возможности добавляются в наследуемые объекты. Подозрительный дизайн удаляет старые возможности во время наследования без добавления новых. Но правила могут нарушаться, и если Вы работаете из старой библиотеки класса, то было бы лучше ограничить существующий класс в его подклассе так что бы была возможность переработать иерархию наследования, что бы ваш класс был там, где ему положено быть - над старым классом.
  • Используйте шаблоны проектировки, что бы исключить "голую функциональность". Это означает, что если вам нужен только один созданный объект вашего класса, то добавьте комментарий "Создавайте только один". Оберните его в одноэлементное множество (синглтон). Если же у вас имеется много грязного кода в вашей главной программе, которая создает ваши объекты, то, обратитесь к шаблонам создания, например, к методам предприятия, с помощью которых Вы и можете реализовать это создание. Исключение "голой функциональности" не только сделает ваш код более легким для понимания и поддержки, оно так же сделает его более пуленепробиваемым против "доброжелателей" пришедших после вас.
  • Остерегайтесь аналитического паралитизма. Запомните, что Вы должны обычно продвигаться в перед в проекте до того, как Вы узнаете все о нем, а лучшим способом при этом будет узнавать то, что Вы не знаете до того, как Вы к этому приступите. Вы не будете знать решения до того, как Вы получите его. Java сделана по принципу файрволов (брендмауеров), дайте им поработать в ваших интересах. Ваши ошибки в классе или наборе классов не разрушат целостность всей системы.
  • Когда Вы думаете, что Вы хорошо проанализировали систему, создали отличный проект или его реализацию, то критично оцените (проанализируйте ее сквозным методом) всю систему целиком. Покажите систему какому - либо стороннему лицу, кто не участвовал в разработке или консультациях. Взгляд на систему парой "новых" глаз зачастую помогает выявить недостатки и недоделки.



  • Начало  Назад  Вперед



    Книжный магазин