1. Введение
В разработке программного обеспечения шаблон проектирования описывает установленное решение наиболее часто встречающихся проблем при разработке программного обеспечения. Он представляет собой лучшие практики, разработанные в течение длительного периода путем проб и ошибок опытными разработчиками программного обеспечения.
Шаблоны проектирования приобрели популярность после того, как в 1994 году Эрих Гамма, Джон Влиссидес, Ральф Джонсон и Ричард Хелм (также известные как Банда четырех или GoF) опубликовали книгу « Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения ».
В этой статье мы рассмотрим творческие шаблоны проектирования и их типы. Мы также рассмотрим некоторые примеры кода и обсудим ситуации, когда эти шаблоны подходят для нашего дизайна.
2. Шаблоны креативного дизайна
Креативные шаблоны проектирования связаны со способом создания объектов. Они уменьшают сложность и нестабильность, создавая объекты контролируемым образом.
Новый оператор
часто считается вредным, так как он разбрасывает объекты по всему приложению. Со временем может стать сложно изменить реализацию, потому что классы становятся тесно связанными.
Порождающие шаблоны проектирования решают эту проблему, полностью отделяя клиента от фактического процесса инициализации.
В этой статье мы обсудим четыре типа творческого шаблона проектирования:
- Singleton — гарантирует, что во всем приложении существует не более одного экземпляра объекта.
- Фабричный метод — создает объекты нескольких связанных классов без указания точного объекта, который необходимо создать.
- Абстрактная фабрика — создает семейства связанных зависимых объектов.
- Builder — строит сложные объекты, используя пошаговый подход.
Теперь давайте подробно обсудим каждый из этих шаблонов.
3. Одноэлементный шаблон проектирования
Шаблон проектирования Singleton предназначен для проверки инициализации объектов определенного класса, гарантируя, что только один экземпляр объекта существует во всей виртуальной машине Java.
Класс Singleton также предоставляет одну уникальную глобальную точку доступа к объекту, так что каждый последующий вызов точки доступа возвращает только этот конкретный объект.
3.1. Пример одноэлементного шаблона
Хотя шаблон Singleton был представлен GoF, исходная реализация, как известно, проблематична в многопоточных сценариях.
Итак, здесь мы собираемся следовать более оптимальному подходу, использующему статический внутренний класс:
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
Здесь мы создали статический
внутренний класс, который содержит экземпляр класса Singleton
. Он создает экземпляр только тогда, когда кто-то вызывает метод getInstance()
, а не при загрузке внешнего класса.
Это широко используемый подход для класса Singleton, поскольку он не требует синхронизации, является потокобезопасным, обеспечивает ленивую инициализацию и имеет сравнительно меньше шаблонов.
Также обратите внимание, что у конструктора есть модификатор доступа private .
Это требование для создания Singleton, поскольку общедоступный
конструктор означает, что любой может получить к нему доступ и начать создавать новые экземпляры.
Помните, что это не оригинальная реализация GoF. Оригинальную версию можно найти в этой связанной статье ForEach об синглтонах в Java.
3.2. Когда использовать шаблон проектирования Singleton
- Для ресурсов, которые дорого создавать (например, объекты подключения к базе данных)
- Хорошей практикой является сохранение всех регистраторов как синглтонов, что повышает производительность.
- Классы, предоставляющие доступ к параметрам конфигурации приложения.
- Классы, содержащие ресурсы, доступ к которым осуществляется в общем режиме.
4. Шаблон проектирования фабричного метода
Фабричный шаблон проектирования или фабричный метод проектирования является одним из наиболее часто используемых шаблонов проектирования в Java.
Согласно GoF, этот шаблон «определяет интерфейс для создания объекта, но позволяет подклассам решать, какой класс создавать. Метод Factory позволяет классу отложить создание экземпляра до подклассов».
Этот шаблон делегирует ответственность за инициализацию класса от клиента конкретному классу фабрики путем создания типа виртуального конструктора.
Для этого мы полагаемся на фабрику, которая предоставляет нам объекты, скрывая фактические детали реализации. Доступ к созданным объектам осуществляется через общий интерфейс.
4.1. Пример шаблона проектирования фабричного метода
В этом примере мы создадим интерфейс Polygon
, который будет реализован несколькими конкретными классами. PolygonFactory будет
использоваться для выборки объектов из этого семейства:
Давайте сначала создадим интерфейс Polygon :
public interface Polygon {
String getType();
}
Далее мы создадим несколько реализаций, таких как Square
, Triangle и
т. д., которые реализуют этот интерфейс и возвращают объект типа Polygon
.
Теперь мы можем создать фабрику, которая принимает количество сторон в качестве аргумента и возвращает соответствующую реализацию этого интерфейса:
public class PolygonFactory {
public Polygon getPolygon(int numberOfSides) {
if(numberOfSides == 3) {
return new Triangle();
}
if(numberOfSides == 4) {
return new Square();
}
if(numberOfSides == 5) {
return new Pentagon();
}
if(numberOfSides == 7) {
return new Heptagon();
}
else if(numberOfSides == 8) {
return new Octagon();
}
return null;
}
}
Обратите внимание, как клиент может полагаться на эту фабрику, чтобы предоставить нам соответствующий Polygon
без необходимости непосредственной инициализации объекта.
4.2. Когда использовать шаблон проектирования Factory Method
- Когда ожидается, что реализация интерфейса или абстрактного класса будет часто меняться
- Когда текущая реализация не может комфортно вместить новые изменения
- Когда процесс инициализации относительно прост, а конструктору требуется всего несколько параметров
5. Шаблон проектирования абстрактной фабрики
В предыдущем разделе мы увидели, как можно использовать шаблон проектирования «Фабричный метод» для создания объектов, относящихся к одному семейству.
Напротив, шаблон проектирования Abstract Factory используется для создания семейств связанных или зависимых объектов. Его также иногда называют фабрикой фабрик.
Для подробного объяснения ознакомьтесь с нашим руководством по абстрактной фабрике .
6. Шаблон проектирования "Строитель"
Шаблон проектирования Builder — это еще один творческий шаблон, предназначенный для построения сравнительно сложных объектов.
Когда сложность создания объекта увеличивается, шаблон Builder может отделить процесс создания экземпляра, используя другой объект (построитель) для создания объекта.
Затем этот построитель можно использовать для создания многих других подобных представлений, используя простой пошаговый подход.
6.1. Пример шаблона построителя
Оригинальный шаблон проектирования Builder, представленный GoF, ориентирован на абстракцию и очень хорош при работе со сложными объектами, однако его дизайн немного сложен.
Джошуа Блох в своей книге «Эффективная Java» представил улучшенную версию шаблона построителя, которая является чистой, легко читаемой (поскольку она использует плавный дизайн ) и простой в использовании с точки зрения клиента. В этом примере мы обсудим эту версию.
В этом примере есть только один класс BankAccount
, который содержит построитель как статический
внутренний класс:
public class BankAccount {
private String name;
private String accountNumber;
private String email;
private boolean newsletter;
// constructors/getters
public static class BankAccountBuilder {
// builder code
}
}
Обратите внимание, что все модификаторы доступа к полям объявлены закрытыми
, поскольку мы не хотим, чтобы внешние объекты обращались к ним напрямую.
Конструктор также является закрытым
, поэтому доступ к нему может получить только строитель, назначенный этому классу. Все свойства, установленные в конструкторе, извлекаются из объекта построителя, который мы передаем в качестве аргумента.
Мы определили BankAccountBuilder
в статическом
внутреннем классе:
public static class BankAccountBuilder {
private String name;
private String accountNumber;
private String email;
private boolean newsletter;
public BankAccountBuilder(String name, String accountNumber) {
this.name = name;
this.accountNumber = accountNumber;
}
public BankAccountBuilder withEmail(String email) {
this.email = email;
return this;
}
public BankAccountBuilder wantNewsletter(boolean newsletter) {
this.newsletter = newsletter;
return this;
}
public BankAccount build() {
return new BankAccount(this);
}
}
Обратите внимание, что мы объявили тот же набор полей, что и внешний класс. Любые обязательные поля необходимы в качестве аргументов для конструктора внутреннего класса, а остальные необязательные поля можно указать с помощью методов установки.
Эта реализация также поддерживает гибкий подход к проектированию, поскольку методы установки возвращают объект построителя.
Наконец, метод сборки вызывает закрытый конструктор внешнего класса и передает себя в качестве аргумента. Возвращенный BankAccount
будет создан с параметрами, заданными BankAccountBuilder
.
Давайте посмотрим на быстрый пример шаблона Builder в действии:
BankAccount newAccount = new BankAccount
.BankAccountBuilder("Jon", "22738022275")
.withEmail("jon@example.com")
.wantNewsletter(true)
.build();
6.2. Когда использовать шаблон построителя
- Когда процесс создания объекта чрезвычайно сложен, с большим количеством обязательных и необязательных параметров
- Когда увеличение количества параметров конструктора приводит к большому списку конструкторов
- Когда клиент ожидает различных представлений для созданного объекта
7. Заключение
В этой статье мы узнали о творческих шаблонах проектирования в Java. Мы также обсудили их четыре различных типа, т. е. Singleton, Factory Method, Abstract Factory и Builder Pattern, их преимущества, примеры и когда мы должны их использовать.
Как всегда, полные фрагменты кода доступны на GitHub .