Software Design Общие практики Бреслав А. А. Основные проблемы Сложность задачи Сильные зависимости между частями системы Трудно рассматривать одну часть системы отдельно от других Дублирование (не только кода, но и структуры, идей и т.д.) Решение не умещается в голове целиком Одно и то же реализовано в нескольких местах. Возможно, по-разному. Запутанность Трудно разобраться в том, что уже создано Одна из причин - дублирование Бреслав А. А. Паттерны проектирования. Введение Принципы решения (1) Сложность задачи Сильные зависимости между частями системы Декомпозиция (разбиение на более мелкие подзадачи) Модульность (каждый модуль решает свою четко поставленную задачу) Инкапсуляция – зависимости только от интерфейса Логичное разбиение на замкнутые модули Дублирование (не только кода, но и структуры, идей и т.д.) Повторное использование Использование стандартной библиотеки Улучшение дизайна, если повторное использование затруднено Бреслав А. А. Паттерны проектирования. Введение Принципы решения (2) Запутанность Модули не смешивают ответственности Устранение дублирования Единство дизайна Самодокументирующийся код Метафоры Конвенции кодирования Использование идиом языка Отсутствие ненужной оптимизации Отсутствие ненужных обобщений Документация Бреслав А. А. Паттерны проектирования. Введение Общий принцип Красота спасет мир от засилья интеллекта Если все написано красиво (просто, понятно и удобно), все будет хорошо. Бреслав А. А. Паттерны проектирования. Введение Важная рекомендация Не ленитесь думать Ленитесь писать код Думайте о логичной декомпозиции устранении дублирования Опасайтесь дырявых абстракций например, вызов виртуального метода в конструкторе слишком трудоемкого обобщения преждевременной оптимизации преждевременной пессимизации Бреслав А. А. Паттерны проектирования. Введение Пессимизация Использование медленных алгоритмов, когда более быстрые реализуются ничуть не сложнее конкатенация строк в цикле использование synchronized без необходимости прямой доступ к элементам LinkedList Бреслав А. А. Паттерны проектирования. Введение Закон дырявых абстракций ЛЮБАЯ НЕТРИВИАЛЬНАЯ АБСТРАКЦИЯ В КАКОЙ-ТО МЕРЕ ЯВЛЯЕТСЯ ДЫРЯВОЙ. ВСЕГДА НАДО ДУМАТЬ О ТОМ, КАК РЕАЛИЗОВАНА ТА ИЛИ ИНАЯ АБСТРАКЦИЯ. Бреслав А. А. Паттерны проектирования. Введение Еще одна проблема Изменяющиеся требования Заказчик никогда не может точно сказать, что именно ему нужно С новыми версиями добавляется новая функциональность, о которой не было известно во время работы над предыдущими версиями Бреслав А. А. Паттерны проектирования. Введение Расширяемость Что нам поможет Инкапсуляция – можно заменить простую реализацию более сложной, не меняя клиентов Модульность – точно известно, кто за что отвечает, и куда что добавить Логичная структура классов Бреслав А. А. Паттерны проектирования. Введение Иерархии классов Каждый класс должен описывать определенное понятие (модульность) не больше, не меньше Подклассы должны уточнять то, что определено суперклассом Наследование – отношение частного случая: подкласс – частный случай суперкласса При других отношениях между понятиями наследование применять нельзя Бреслав А. А. Паттерны проектирования. Введение Повторное использование Наследование – мощный инструмент повторного использования Но, если один класс не является частным случаем другого, а лишь использует все его умения, лучше использовать агрегацию хранить объект используемого класса внутри объекта использующего класса Бреслав А. А. Паттерны проектирования. Введение Инкапсуляция Необходимо максимально инкапсулировать реализацию прятать ВСЕ поля, по возможности даже от наследников использовать максимально абстрактные ссылки предоставлять минимальный API Бреслав А. А. Паттерны проектирования. Введение Software Design Хороший код Бреслав А. А. Не устану повторять… Избегать дублирования Избегать ненужных обобщений Избегать ненужной оптимизации Избегать ненужной пессимизации Инкапсулировать все, что можно Опасаться дырявых абстракций Бреслав А. А. Паттерны проектирования. Введение Внесение изменений в код Каждая модификация кода потенциально вносит ошибку Важно минимизировать количество изменений, необходимых для добавления/исправления чего бы то ни было Ошибки должны появляться там, где мы вносили изменения, а не где-то еще Бреслав А. А. Паттерны проектирования. Введение Как минимизировать изменения Логичное разбиение задачи на модули если для того, чтобы что-то сделать, нужно изменить что-то в трех местах, то, возможно, эти три места являют собой один модуль Инкапсуляция Если при изменении реализации не меняется API, нам не придется менять код клиентов Бреслав А. А. Паттерны проектирования. Введение Практики кодирования Объявлять переменные только в тот момент, когда они становятся нужны и сразу инициализировать Не заводить лишних полей поле – это почти глобальная переменная Использовать именованные константы повторение литералов в коде – дублирование поди найди, где нужно изменить, если значение изменилось Бреслав А. А. Паттерны проектирования. Введение Максимально абстрактные ссылки Если нужен просто список – напишите List Это дает возможность, не изменяя клиентского кода, заменить одну реализацию списка другой – в инициализации переменной. Если нужен динамический массив – напишите ArrayList. Не вводите клиентов в заблуждение Здесь нельзя безболезненно заменить реализацию Бреслав А. А. Паттерны проектирования. Введение Опасная перегрузка class Thing { public boolean equals(Object other) { return super.equals(other); } } Добавим еще метод: public boolean equals(Thing other) { return this.field == other.field; } Что плохого? Бреслав А. А. Паттерны проектирования. Введение Как избегать проблем при перегрузке Не определять несколько перегруженных методов с одинаковым числом параметров Вообще не злоупотреблять перегрузкой Бреслав А. А. Паттерны проектирования. Введение Зависимости между методами Если методы обмениваются информацией через поля, это может вести к ошибкам Методы должны по возможности общаться через параметры и возвращаемые значения Лучший метод – метод без побочных эффектов Бреслав А. А. Паттерны проектирования. Введение Когда использовать поля Поле – это элемент состояния объекта Понятие, реализуемое классом, характеризуется некоторым атрибутом По возможности значение атрибутов (полей) не должно влиять на поведение объекта Бреслав А. А. Паттерны проектирования. Введение Другие проблемы с полями Недостаточная инициализация После создания объекта, он еще не готов к использованию, потому что некоторые поля не проинициализированы Например, для завершения инициализации нужно вызвать специальный метод Клиент никогда до этого не додумается Конструктор должен создавать полностью пригодный к использованию объект Бреслав А. А. Паттерны проектирования. Введение Неизменяемость Нужно использовать final для полей, когда только возможно гарантируется полная инициализация можно кешировать вычисляемые значения методы не имеют побочных эффектов Все классы данных по возможности должны быть полностью неизменяемыми Бреслав А. А. Паттерны проектирования. Введение Когда класс неизменяем Все поля final Не хранятся ссылки на объекты, полученные извне Наружу не возвращаются ссылки на значения полей Полезно использовать new ArrayList(Collection c) array.clone() Collections.unmodifiableCollection() Бреслав А. А. Паттерны проектирования. Введение Проблема нулевого флага По возможности метод не должен возвращать null Неожиданные NPE далеко от источника ошибки Нет информации об ошибке Варианты Бросить исключение Вернуть Null Object Бреслав А. А. Паттерны проектирования. Введение Null Object Объект, означающий «отсутствие объекта» поддерживает интерфейс абстракции методы не делают ничего или кидают исключения Позволяет клиенту не обрабатывать ошибку вообще Лист в дереве Маркер конца списка Бреслав А. А. Паттерны проектирования. Введение Источники Макконнелл С., Совершенный код. Мастер-класс / Пер. с англ. – М.: Издательско-торговый дом «Русская редакция»; СПб.: Питер, 2005. – 896 стр.: ил. Кент Бек, Экстремальное программирование. – СПб.: Питер, 2002 –224 с.: ил. Эрик Аллен, Типичные ошибки проектирования. Библиотека программиста – СПб.: Питер, 2003. – 224 с.: ил. Джоэл Спольски, Джоэл о программировании… – СПб: Символ-Плюс, 2006 – 352 с., ил. Джошуа Блох, Java™. Эффективное программирование / Пер. с англ. – М.: Лори, 2002 Бреслав А. А. Паттерны проектирования. Введение Задание Описать интерфейс двоичного дерева поиска (из произвольных элементов с естественным порядком) создание пустого дерева создание дерева из массива (списка) элементов добавление проверка наличия элемента поиск минимума/максимума количество вершин проверка на пустоту Создать две реализации: Хранение элементов в динамическом Каждая вершина – отдельный объект Бреслав А. А. Паттерны проектирования. Введение массиве Вопросы Бреслав А. А. Паттерны проектирования. Введение