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



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


226   0  

Comments

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