Elegant Objects - Yegor Bugayenko
Refs:
Глава 1 Рождение
Сопровождаемость — важное качество любого программного обеспечения, оно может быть измерено как время, необходимое для того, чтобы понять ваш код. Чем больше времени требуется, тем ниже сопровождаемость и тем хуже код. Я бы даже сказал: если я вас не понимаю, то виноваты в этом вы. Понимая объекты и их роль в ООП, вы повысите сопровождаемость своего кода. Он станет короче, проще для восприятия, модульнее, целостнее и т. д. Он станет лучше, а в большинстве случаев и дешевле.
1.1 Не используйте имена заканчивающиеся на -er
Класс — это фабрика объектов.
Класс создает объекты, обычно говорят — инстанцирует их.
Инстанцирование отличается от того, что мы называем паттерном Factory, но только потому, что оператор new в Java не настолько функционален, насколько мог бы быть.
Оператор new — простейший механизм управления фабрикой объектов.
Паттерн проектирования «Фабрика» в Java работает как расширение оператора new. Он делает оператор более гибким и функциональным, присоединяя к нему дополнительную логику.
Я хочу, чтобы вы представляли себе класс как склад объектов, которые можно брать оттуда при необходимости и возвращать, когда потребность в них исчезает.
Имя класса не должно происходить от названия функциональности, предоставляемой его объектами! Напротив, класс должен быть назван на основе того, чем он является, а не того, что он делает.
Объект — это представитель инкапсулированных в нем данных.
Когда приходит время давать имя новому классу, думайте о том, что он есть, а не о том, что он делает.
Я считаю, что паттерн Builder плох, поскольку он поощряет создание крупных объектов. Идеальный объект не должен инкапсулировать более 1-4 свойств. Определенно не больше пяти. Builder создан, чтобы помочь нам строить более крупные объекты. Следовательно, его использование - очень плохая идея.
1.2. Сделайте один конструктор главным
Конструктор - точка входа нового объекта. Он принимает несколько аргументов и что-то делает с ними, чтобы подготовить объект к выполнению своих обязанностей.
Если вы правильно проектируете свои классы (в соответствии с рекомендациями из последующих разделов), то у них будет много конструкторов и немного методов (не более 5 методов).
Большое количество методов приводит к размыванию фокуса и нарушению принципа единственности ответственности.
Основная задача конструктора - инициализировать инкапсулированные свойства, используя переданные ему аргументы.
Перегрузку методов - механизм объявления методов или конструкторы с одинаковыми именами, но разными наборами аргументов.
1.3. В конструкторах не должно быть кода
Инициализация объекта не должна содержать код и затрагивать аргументы. Вместо этого она должна при необходимости оборачивать их или инкапсулировать в необработанном виде.
При истинном объектно-ориентированном подходе инстанцирование объекта подразумевает компоновку меньших объектов в один более крупный.
Инстанцирование объекта не делает ничего, кроме его сборки, реальная работа выполняется методами объекта.
Облегченные конструкторы упрощают создание объектов, делая их более настраиваемыми и прозрачными.
Глава 2 Образование
Маленький объект - это элегантный и хорошо сопровождаемый объект. В ООП не может быть никакого оправдания классу в 1000 строк кода
2.1. Инкапсулируйте как можно меньше
Чем выше сложность, тем хуже сопровождаемость, тем больше потери денег и времени и тем меньше удовлетворенных потребителей.
Поэтому я рекомендую инкапсулировать не более четырех объектов. Если вам нужно инкапсулировать больше объектов, значит, с вашим классом что-то не так и он нуждается в рефакторинге. Без исключения. Не больше четырех.
Набор инкапсулированных объектов называется состоянием или идентичностью объекта.
В Java, как и в С++, идентичность объекта отделена от его состояния. Два объекта, х и у, имеют одинаковое состояние, но разные идентичности,
Насколько я понимаю, объект в ООП - это агрегат из других объектов, работающих совместно для получения более высокоуровневого поведения.
В Java и почти во всех остальных ООП-языках объект - это всего лишь набор данных с прикрепленными к нему методами. Что-то вроде оболочки, где можно хранить данные.
Чтобы устранить упомянутый недостаток Java, советую вам избегать оператора == и всегда переопределять метод equals().
2.2. Инкапсулируйте хотя бы что-нибудь
Суть инкапсуляции - в делегировании ответственности объекту. Таким образом объект получает право управлять своими (и не только) данными удобным для себя способом.
2.3. Всегда используйте интерфейсы
Объекты взаимосвязаны, поскольку они нуждаются друг в друге. Каждый объект должен делать и какие услуги предоставлять другим объектам, все просто. Но когда приложение начинает разрастаться и количество объектов превышает несколько десятков, тесная связь между ними становится серьезной проблемой. И эта проблема влияет на сопровождаемость. Всё сводится к сопровождаемости. Она важнее всего остального, включая производительность.
Чтобы повысить сопровождаемость приложения в целом, мы должны приложить максимум усилий к расцеплению (decoupling) объектов. Технически это означает возможность модифицировать объект, не модифицируя связанные с ним объекты. Лучший инструмент для этого - интерфейсы.
Интерфейс - это контракт, которому должен подчиняться объект, чтобы общаться с другими объектами.
Грамотно спроектированный класс не должен содержать публичных методов, которые не реализуют хотя бы один интерфейс.
Небольшое философское замечание: класс существует только потому, что кому-то нужны его услуги. Эти услуги должны быть где-то документированы, например в контракте (интерфейсе). Кроме того, между поставщиками услуг должна существовать конкуренция. Именно в этом суть нескольких классов, реализующих один и тот же интерфейс. Каждый из конкурентов должен быть легко заменяем другим. В этом и заключается суть слабого сцепления.
На сегодняшний день больше не стоит задействовать абстрактные классы.
PowerMock - неплохой инструмент, но его нужно использовать очень аккуратно и очень редко. Почти никогда. Если вам нужно его применять, ваш код плохо написан. Перепишите его.
2.4. Тщательно выбирайте имена методов.
Я предлагаю следующее эмпирическое правило: “строителей” называть именами существительными, “манипуляторов” - глаголами. Этот совет очень похож на предложенную Бертраном Мейером (Bertrand Meyer) в книге “Объектно-ориентированное конструирование программных систем” идею, состоящую в разделении методов объекта на две непересекающиеся категории - запросы и команды.
Строители - это существительные
Грамотно названный метод помогает его пользователям понять, для чего был создан объект, каковы его миссия, цель существования и смысл жизни. Неграмотно названный метод может разрушить представление об объекте и способствовать тому, что его станут использовать как мешок с данными и набором процедур.
Манипуляторы - это глаголы
Только метод-строитель может возвращать значения, и его имя должно быть существительным. Если объект позволяет нам выполнять преобразования, его имя должно быть глаголом и он не должен ничего возвращать.
Вместо того чтобы использовать паттерн «Строитель, стоит разбить сложные объекты на несколько более простых.
Во-первых, знайте миссию своего метода. Он либо строитель, либо манипулятор. И ни в коем случае не может выполнять обе роли. Во-вторых, называйте строители именами существительными, а манипуляторы - именами прилагательными. Единственным исключением будет строитель, который возвращает логическое значение. В таком случае применяйте прилагательные.
2.5. Не используйте публичные константы
Объекты не должны ничего использовать совместно - они должны быть самодостаточными и очень закрытыми. Механизм совместного использования противоречит идее инкапсуляции и объектно-ориентированному образу мышления в целом.