Продолжение серии постов об основных идеях книги Effective Java (2-е издание).
Item 13. Минимизируйте доступность классов и их членов.
Известное правило: каждый класс, метод или поле класса нужно делать настолько недоступными, насколько это возможно. Другими словами, необходимо минимизировать открытость вашей программы до тех пор, пока это возможно для использования её по назначению.
Item 14. В открытых (public) классах всегда используйте гетеры и сетеры (getters and setters) вместо открытых полей.
Открытые классы никогда не должны обеспечивать прямой доступ к своим полям, чтобы не позволить нарушить целостность данных. В меньшей степени это относится к неизменяемым (immutable) полям, однако, прежде, чем открыть доступ к такому полю, следует помнить, что публичный API класса нельзя будет изменить в будущем.
Если класс приватный (private) или пакето-приватный (package-private), то допустимо применение прямого доступа к полям.
Item 15. Старайтесь писать неизменяемые (immutable) классы.
Этому есть несколько причин:
В начале параграфа приводится необходимое и достаточное условие того, чтобы класс был неизменяемым.
Item 16. Предпочитайте композицию вместо наследования.
Наследование - мощный инструмент, но, будучи применённым неправильно, может сделать программу уязвимой. Наследование вполне допустимо, если суперкласс и наследники находятся под контролем одних и тех же программистов. В ином случае возникает опасность.
Наследование нарушает инкапсуляцию. Чтобы правильно отнаследоваться от класса, нужно знать, как он работает. Таким образом, если изменится суперкласс, его подклассы могут перестать функционировать. Поэтому каждый класс должен быть либо спроектирован для наследования от него клиентским кодом, либо такое наследование должно быть запрещено.
Зачастую, можно отказаться от наследования, заменив его композицией, то есть вместо подкласса написав т.н. класс-обёртку (wrapper).
Item 17. Проектируйте и документируйте возможность наследования от класса, либо запрещайте это наследование.
Если предполагается, что от класса будут наследоваться, то нужно документировать не только то, что перегружаемые методы делают, но и то, как они это делают. Безусловно, это нарушает инкапсуляцию.
Кроме того, необходимо открыть доступ к некоторым внутренностям такого класса с помощью модификатора protected.
Есть ещё один важный момент: ни конструктор, ни методы clone, readObject не должны вызывать перегружаемые методы, прямо или косвенно. В книге приводится хороший пример, демонстрирующий это.
Item 18. Предпочитайте интерфейсы абстрактным классам.
Поскольку Java не поддерживает множественное наследование, применение абстрактных классов сильно ограничено по сравнению с интерфейсами. Вообще, у интерфейсов много преимуществ по сравнению с абстрактными классами, достаточно очевидных, но есть и недостаток: внести изменения в уже существующий, широко применяемый интерфейс практически невозможно.
Стоит заметить возможность комбинирования преимуществ абстрактных классов и интефейсов путём введения т.н. skeletal implementation. Наиболее известные примеры этого - AbstractCollection, AbstractMap, AbstractSet и AbstractList.
Item 19. Используйте интерфейсы только для определения типов.
Другими словами, не нужно их использовать не по назначению, например, для хранения значений констант.
Item 20. Предпочитайте иерархии классов вместо tagged классов.
Под tagged классом имеется в виду такой класс, который содержит некоторое поле-тег, определяющее его поведение. Приведён пример такой реализации класса Shape, в котором есть поле shape, определяющее конкретную форму объекта. Такой подход имеет ряд недостатков и не имеет значительных преимуществ. Вместо этого рекомендуется строить иерархию классов. В данном случае следовало бы организовать абстрактный класс Figure, в котором объявляются основные методы, и классы-наследники, каждый из которых представляет конкретную фигуру.
Item 21. Используйте объекты-функции (function objects) для представления стратегий (strategies).
Шаблон проектирования Стратегия стоит использовать, когда необходимо определить поведение некоторой функции путём передачи ей другой функции. Ярким примером использования этого шаблона в Java является интерфейс Comparator.
Item 22. Предпочитайте статические внутренние классы вместо нестатических.
Есть 4 типа внутренних классов: статические, нестатические, анонимные и локальные. Каждый из этих типов имеет своё применение, о чём и рассказано в параграфе.
Хотелось бы отметить следующее: синтаксически разница между статическими и нестатическими внутренними классами очень мала - первый объявлен с модификатором static, второй - нет. Однако, на деле эти два типа имеют значительные различия. Общее правило для выбора между ними таково: если внутренний класс не требует доступа к содержащему его экземпляру, то следует использовать статический класс.
Item 13. Минимизируйте доступность классов и их членов.
Известное правило: каждый класс, метод или поле класса нужно делать настолько недоступными, насколько это возможно. Другими словами, необходимо минимизировать открытость вашей программы до тех пор, пока это возможно для использования её по назначению.
Item 14. В открытых (public) классах всегда используйте гетеры и сетеры (getters and setters) вместо открытых полей.
Открытые классы никогда не должны обеспечивать прямой доступ к своим полям, чтобы не позволить нарушить целостность данных. В меньшей степени это относится к неизменяемым (immutable) полям, однако, прежде, чем открыть доступ к такому полю, следует помнить, что публичный API класса нельзя будет изменить в будущем.
Если класс приватный (private) или пакето-приватный (package-private), то допустимо применение прямого доступа к полям.
Item 15. Старайтесь писать неизменяемые (immutable) классы.
Этому есть несколько причин:
- неизменяемые классы просты для понимания и применения;
- они не требуют синхронизации многопоточного доступа;
- их компоненты также неизменяемы, их можно использовать и в других экземплярах класса, избегая копирования;
- облегчают поддержание инвариантов других, более сложных объектов.
В начале параграфа приводится необходимое и достаточное условие того, чтобы класс был неизменяемым.
Item 16. Предпочитайте композицию вместо наследования.
Наследование - мощный инструмент, но, будучи применённым неправильно, может сделать программу уязвимой. Наследование вполне допустимо, если суперкласс и наследники находятся под контролем одних и тех же программистов. В ином случае возникает опасность.
Наследование нарушает инкапсуляцию. Чтобы правильно отнаследоваться от класса, нужно знать, как он работает. Таким образом, если изменится суперкласс, его подклассы могут перестать функционировать. Поэтому каждый класс должен быть либо спроектирован для наследования от него клиентским кодом, либо такое наследование должно быть запрещено.
Зачастую, можно отказаться от наследования, заменив его композицией, то есть вместо подкласса написав т.н. класс-обёртку (wrapper).
Item 17. Проектируйте и документируйте возможность наследования от класса, либо запрещайте это наследование.
Если предполагается, что от класса будут наследоваться, то нужно документировать не только то, что перегружаемые методы делают, но и то, как они это делают. Безусловно, это нарушает инкапсуляцию.
Кроме того, необходимо открыть доступ к некоторым внутренностям такого класса с помощью модификатора protected.
Есть ещё один важный момент: ни конструктор, ни методы clone, readObject не должны вызывать перегружаемые методы, прямо или косвенно. В книге приводится хороший пример, демонстрирующий это.
Item 18. Предпочитайте интерфейсы абстрактным классам.
Поскольку Java не поддерживает множественное наследование, применение абстрактных классов сильно ограничено по сравнению с интерфейсами. Вообще, у интерфейсов много преимуществ по сравнению с абстрактными классами, достаточно очевидных, но есть и недостаток: внести изменения в уже существующий, широко применяемый интерфейс практически невозможно.
Стоит заметить возможность комбинирования преимуществ абстрактных классов и интефейсов путём введения т.н. skeletal implementation. Наиболее известные примеры этого - AbstractCollection, AbstractMap, AbstractSet и AbstractList.
Item 19. Используйте интерфейсы только для определения типов.
Другими словами, не нужно их использовать не по назначению, например, для хранения значений констант.
Item 20. Предпочитайте иерархии классов вместо tagged классов.
Под tagged классом имеется в виду такой класс, который содержит некоторое поле-тег, определяющее его поведение. Приведён пример такой реализации класса Shape, в котором есть поле shape, определяющее конкретную форму объекта. Такой подход имеет ряд недостатков и не имеет значительных преимуществ. Вместо этого рекомендуется строить иерархию классов. В данном случае следовало бы организовать абстрактный класс Figure, в котором объявляются основные методы, и классы-наследники, каждый из которых представляет конкретную фигуру.
Item 21. Используйте объекты-функции (function objects) для представления стратегий (strategies).
Шаблон проектирования Стратегия стоит использовать, когда необходимо определить поведение некоторой функции путём передачи ей другой функции. Ярким примером использования этого шаблона в Java является интерфейс Comparator.
Item 22. Предпочитайте статические внутренние классы вместо нестатических.
Есть 4 типа внутренних классов: статические, нестатические, анонимные и локальные. Каждый из этих типов имеет своё применение, о чём и рассказано в параграфе.
Хотелось бы отметить следующее: синтаксически разница между статическими и нестатическими внутренними классами очень мала - первый объявлен с модификатором static, второй - нет. Однако, на деле эти два типа имеют значительные различия. Общее правило для выбора между ними таково: если внутренний класс не требует доступа к содержащему его экземпляру, то следует использовать статический класс.
Комментариев нет:
Отправить комментарий