Сначала можно представить паттерн как особо умный подход, способный адаптироваться к решению определённого типа задач. То есть, это методика, требующая глобального понимания проблемы. После того как проблема полностью проанализирована во всех её аспектах, предлагается наиболее универсальное и гибкое решение. Возможно, конкретная проблема уже была встречена и решена ранее. Однако, прежние решения могли не быть идеальными, и вы увидите, как они будут представлены в виде паттерна.
Хотя мы называем их "паттернами дизайна", они не ограничиваются областью дизайна. Когда говорят о "паттернах", следует отойти от традиционного анализа, дизайна и реализации. Вместо этого, "паттерн" представляет собой конкретное выражение целого набора идей в программе, поэтому он может появиться на этапе анализа или высшего уровня дизайна. Это очень интересно, так как паттерны имеют форму прямой реализации в коде, поэтому обычно не хочется, чтобы они появились до этапа низкоуровнего дизайна или конкретной реализации (и фактически, люди обычно не осознают необходимости паттерна до тех пор, пока не достигнут этих этапов).Основная концепция паттернов также является основной концепцией программирования: добавление нового уровня абстракции! Каждый раз, когда мы абстрагируем что-то, мы изолируем определённые детали. Основной мотив здесь — отделение изменений, происходящих с тем, что должно остаться неизменным. Другой причиной является то, что если мы обнаруживаем, что часть программы может меняться по одной или другой причине, мы хотим предотвратить распространение этих изменений внутрь кода. Это не только снижает стоимость поддержки кода, но и делает его более понятным (что ещё раз снижает затраты).Для создания мощных и легко поддерживаемых приложений самая сложная часть часто заключается в том, чтобы найти то, что я называю "ведущими изменениями". Это значит, что вам нужно найти самые важные факторы, вызывающие изменения системы, или, другими словами, те части, которые требуют наибольших усилий и затрат. Как только вы определили "ведущие изменения", вы можете сосредоточиться на них и строить свой дизайн вокруг них. Цель паттернов проектирования заключается в разделении изменяемых частей кода от неизменяемых. При таком подходе становится очевидным, что некоторые паттерны уже используются в этой книге. Например, наследование можно рассматривать как паттерн проектирования (подобно тому, как это реализует компилятор): внутри объектов, имеющих одинаковый интерфейс (то есть то, что остается неизменным), позволяет выразить различия поведения (то есть то, что может меняться).Агрегация также может рассматриваться как паттерн, поскольку она позволяет модифицировать — как динамически, так и статически — объекты, используемые для реализации класса, тем самым изменяя способ работы этого класса. В книге «Шаблоны проектирования» можно найти ещё один шаблон — «Итератор». В Java 1.0 и 1.1 его незаслуженно называли «Перечисление», а в Java 1.2 вернули название «Итератор». Когда мы просматриваем коллекцию, выбирая различные элементы последовательно, итератор эффективно скрывает детали реализации коллекции. Благодаря использованию итератора можно писать универсальный код для выполнения операций над всеми элементами последовательности, не заботясь о том, как она была создана. Таким образом, наш универсальный код может работать с любой коллекцией, которая способна предоставить итератор.### 16.1.1 Одиночка
Самым простым шаблоном проектирования является «Одиночка» (Singleton
). Он обеспечивает наличие одного экземпляра объекта. Шаблон одиночки используется в библиотеках Java, но вот пример более прямолинейный:
//: SingletonPattern.java
// Шаблон проектирования "Одиночка": вы никогда не сможете создать больше одного экземпляра.
package c16;
// Поскольку этот класс не наследуется от базового класса Cloneable,
// и клонируемость не добавляется, то объявление класса как final
// препятствует добавлению клонируемости во всех производных классах:
final class Singleton {
private static Singleton s = new Singleton(47);
private int i;
private Singleton(int x) { i = x; }
public static Singleton getHandle() {
return s;
}
public int getValue() { return i; }
public void setValue(int x) { i = x; }
}
public class SingletonPattern {
public static void main(String[] args) {
Singleton s = Singleton.getHandle();
System.out.println(s.getValue());
Singleton s2 = Singleton.getHandle();
s2.setValue(9);
System.out.println(s.getValue());
try {
// Нельзя сделать это: ошибка компиляции.
// Singleton s3 = (Singleton)s2.clone();
} catch(Exception e) {}
}
} ///:~
```Ключевой момент создания одиночки заключается в предотвращении возможности создания клиентским программистом любого другого экземпляра объекта, кроме того, который предоставлен нами. Все конструкторы должны быть объявлены как `private`, и хотя бы один конструктор должен быть создан, чтобы предотвратить автоматическое добавление компилятором синхронизации по умолчанию (которое будет считаться «доброжелательным» — `friendly`, а не `private`). В этот момент следует решить, как создавать свои объекты. Здесь мы выбрали статический способ создания. Однако можно также выбрать вариант ожидания запроса на создание от клиентского программиста, после чего создавать объекты динамически в соответствии с их требованиями. В любом случае, объекты должны храниться как "частные" свойства. Доступ к ним предоставляется через общедоступные методы. Например, `getHandle()` возвращает ссылку на `Singleton`. Оставшиеся интерфейсы (`getValue()` и `setValue()`) являются обычными методами класса. Java также позволяет создать объект через клонирование (`Clone`). В этом примере установка класса как `final` запрещает клонирование. Поскольку `Singleton` наследуется непосредственно от `Object`, метод `clone()` остаётся с модификатором доступа `protected` и его нельзя использовать (его использование приведёт к ошибке компиляции).Однако если мы наследуемся от структуры классов, где метод `clone()` перегружен так, чтобы иметь модификатор доступа `public` и реализовать интерфейс `Cloneable`, то для запрета клонирования нам потребуется перегрузить `clone()`, выбросив исключение `CloneNotSupportedException`, как это было описано в главе 12.
Также можно перегрузить `clone()`, просто вернув `this`. Это может вызвать путаницу, поскольку программист-клиент может ошибочно полагать, что объект ещё не был клонирован и продолжает работать с исходным объектом.
Обратите внимание, что мы не ограничены созданием одного объекта. Эта техника может использоваться для создания пула ограниченного количества объектов. Однако в этом случае могут возникнуть проблемы с совместным использованием объектов внутри пула. Если вы столкнётесь с этой проблемой, вы можете разработать своё решение для регистрации и удаления регистрации общих объектов.
## 16.1.2 Классификация паттернов
Книга "Design Patterns" обсуждает 23 различных паттерна и классифицирует их по трём критериям (все они связаны с аспектами, которые могут меняться):
(1) Создание: способ создания объекта. Обычно это относится к изоляции деталей создания объекта таким образом, чтобы не зависеть от конкретного типа объекта, поэтому при добавлении нового типа объекта не требуется изменения кода.(2) Структура: проектирование объектов для удовлетворения определённых проектных ограничений. Это относится к способу соединения объектов друг с другом, чтобы изменения системы не влияли на эти связи.
(3) Действие: объекты, манипулирующие определёнными действиями в программе. Это требует упаковывания действий, таких как объяснение языка, выполнение запроса, обход последовательности (как в итераторах) или реализация алгоритма. В этой главе представлены примеры паттернов "Наблюдатель" (`Observer`) и "Посетитель" (`Visitor`). Книга «Design Patterns» отводит каждому из этих 23 шаблонов отдельную главу, сопровождая их множеством примеров, большинство из которых написано на C++, а некоторые — на Smalltalk (если вы знакомы с этой книгой, то знаете, что это не является большой проблемой, так как основные концепции легко переводятся с двух этих языков на Java). В данной книге нет необходимости повторять все эти шаблоны, поскольку они подробно рассмотрены в «Design Patterns», которая представляет собой самостоятельное произведение. Вместо этого данная глава предоставляет лишь несколько примеров, чтобы дать вам общее представление о шаблонах и понять их значимость.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )