О шаблонах
В этой статье речь пойдет о наборе шаблонов ООП, использующих простую композицию, а не наследование.
Большинство шаблонов взяты из книги Gang of Four: Design Patterns. Мы рассмотрим лишь краткое введение в каждый из них, для более подробного ознакомления перейдите по ссылке.
Шаблон 1: Абстрактная Фабрика
Фабрика — это объект, единственной задачей которого является создание других объектов. Их можно создавать разными способами, однако шаблон абстрактной фабрики — наиболее эффективный вариант.
С помощью этого шаблона можно не только изменять сгенерированный или созданный объект во время выполнения, но и саму фабрику. Он также отлично работает с фреймворками, использующими inversion of control, такими как Spring или Unity.
Код выглядит следующим образом:
interface Factory<T> { T build(Metadata d) } class ClientFactory implements Factory<Client> { Client build(Metadata d) { // Build actual object and return } }
Абстрактные фабрики удобны в использовании, если нужно создать объект, соответствующий простому интерфейсу на основе конфигурации, так, чтобы все остальные классы, использующие этот объект, не знали об изменениях. Основные идеи — это те же классические идеи с другими принципами разработки ПО: скрытие информации, классы, выполняющие одно действие, и небольшие интерфейсы.
Шаблон 2: Делегат
Многие разработчики при работе над определенным проектом (кодом) делегируют работу другим членам команды вместо того, чтобы выполнять ее самостоятельно.
Шаблон делегирования работает по тому же принципу: классы высшего порядка просят классы низшего порядка выполнить работу за них, оставаясь при этом более простыми и зная меньше информации о находящихся ниже структурах.
Код выглядит следующим образом:
interface Validator { bool validate(Object o) } class ValidatorHelper implements Validator { Set<Validator> delegates; bool validate(Object o) { for (Validator v : delegates) { if (!v.validate(o)) return false } return true } } class RestController { ValidationHelper helper; Response addObject(Object o) { if (helper.validate(o)) return ErrorResponse // Normal processing } }
Использование делегатов полезно при работе с валидацией, сортировкой, нормализацией и т. д.
Шаблон 3: Строитель / Именованные параметры
С помощью шаблона строитель можно создать гибкий и расширяемый код без особых усилий и при желании использовать возможности неизменяемости!
Другие языки могут не иметь шаблон строитель (или даже не нуждаться в нем), благодаря наличию именованных параметров в конструкторах со стандартными значениями по умолчанию. Они предоставляют те же возможности: объявление только тех элементов, для которых нужно установить определенное значение.
Код выглядит следующим образом:
class Dto { String s int i private Dto(String s, int i) { this.s = s this.i = i } public DtoBuilder builder() { return new DtoBuilder() } public static class DtoBuilder { private String s = "some string" private int i = 0 public DtoBuilder withString(String s) { this.s = s return this } public DtoBuilder withInt(int it) { this.i = i return this } public Dto build() { return new Dto(s, i) } } }
Примечание: в Java также используется Lombok для выполнения утомительного процесса написания кода.
Причина, по которой этот шаблон так упрощает код, заключается в том, что когда все объекты используют конструктор, создание нового происходит автоматически. Не нужно тратить время на просмотр конструкторов и кода строителя.
Шаблон 4: Обогатитель
Этот шаблон тесно связан с цепочкой ответственности и шаблонным методом. В нем каждая «цепочка» расширяет или дополняет объект, а затем возвращает его. Эти действия можно выполнить с каждым расширителем в цепочке, или же цепочка может пропустить остальную часть при необходимости.
Кажется, что это нарушает правила чистого кода о побочных эффектах в функции. Однако это не так, поскольку расширитель должен возвращать расширенный объект вызывающему объекту, заявляя, что объект может измениться. Насколько известно вызывающему объекту, это может быть новый объект (особенно в случае неизменяемых ограничений).
interface Enricher<T> { T enrich(T thing); } class HeadersEnricher implements Enricher<Headers> { Headers enrich(Headers headers) { headers.add("x-header", "something") return headers } }
Этот шаблон отлично подходит для наполнения объекта новым состоянием. Например, если у вас есть объект, поступающий из потока Kafka, к которому необходимо добавить данные, прежде чем сохранить в хранилище данных.
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming