суббота, 21 октября 2017 г.

О строителях

Сегодня речь пойдет о шаблоне проектирования Builder, или же по русски, строитель.
Начнем с определения и выясним для чего он нужен.

Строитель относится к порождающим шаблонам, а значит, с его помощью создаются объекты. Он позволяет конструировать объект по частям. Приведу пример, как выглядит типичный Builder.
Допустим у нас есть класс Person
Чтобы сконструировать объект данного класса требуется знать имя и возраст. Builder для этого класса представляет некий промежуточный объект, хранящий все эти параметры.

В данном случае, он выглядит несколько избыточным, но когда параметров становится больше и/или когда в момент создания требуется выполнить некоторые проверки либо дополнительные операции, то преимущества шаблона становятся более очевидными. Логика создания объектов класса Person выносится из самого класса в класс-строителя. Тем самым мы не перегружаем Person дополнительной функциональностью.
Создать объект теперь можно так:

Заметим, что порядок вызова методов для выставления параметров не задан. Не всегда такого подходит, например, в случае, если проверка значения параметра зависит от значения другого параметра. Тогда можно воспользоваться следующим приемом:
Что здесь происходит? После выставления какого либо параметра возвращается объект класса, имеющего только один метод. Таким образом мы задаем порядок вызова:

  1. выставить имя
  2. выставить возраст
  3. создать объект
И что не маловажно мы добились того, что проверка порядка осуществляется на этапе компиляции.

Согласитесь, что данный код, выглядит не очень читабельно. Улучить восприятие можно переименовав методы, создавая конструкции похожиe на естественный язык, например:
Но это потребует больше кода и больше времени над продумываем api 🙂 Естественно, код реализующий подобное, здесь я приводить не буду.

Порой возникает потребность в наследовании строителей. Например, базовый класс расширяется, обрастая наследниками, хочется переиспользовать уже созданный для него строитель. Допустим, есть наследник с именем Citizen: Базовый строитель имеет следующую структуру:
Тогда строитель для класса Person выглядит так:
А для Citizen так:
Создание объектов данных классов по прежнему осталось такое же простое, как и в предыдущих случаях: