4 лучших шаблона для написания простого кода


О шаблонах

В этой статье речь пойдет о наборе шаблонов ООП, использующих простую композицию, а не наследование.

Большинство шаблонов взяты из книги 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, к которому необходимо добавить данные, прежде чем сохранить в хранилище данных.


Перевод статьи Dan Goslen: My Top 4 Patterns for Writing Simple Code


Поделиться статьей:


Вернуться к статьям

Комментарии

    Ничего не найдено.