Software Design Общие практики Бреслав А. А.

advertisement
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
Бреслав А. А.
Паттерны проектирования. Введение
Задание

Описать интерфейс двоичного дерева поиска
(из произвольных элементов с естественным
порядком)
 создание
пустого дерева
 создание дерева из массива (списка) элементов
 добавление
 проверка наличия элемента
 поиск минимума/максимума
 количество вершин
 проверка на пустоту

Создать две реализации:
 Хранение элементов в динамическом
 Каждая вершина – отдельный объект
Бреслав А. А.
Паттерны проектирования. Введение
массиве
Вопросы
Бреслав А. А.
Паттерны проектирования. Введение
Download