Паттерн Builder (Строитель) используется для пошагового создания сложных объектов. Он отделяет конструирование объекта от его представления, позволяя использовать один и тот же процесс строительства для разных представлений объекта.
Когда применять Builder
- Когда нужно создавать сложные объекты, состоящие из множества частей.
- Когда нужно изолировать код сборки объекта от его внутренней структуры.
- Когда необходимо обеспечить различные представления создаваемого объекта.
PlantUML-диаграмма
public class Car
{
public string Engine { get; set; }
public int Seats { get; set; }
public bool HasGPS { get; set; }
public override string ToString()
{
return $"Автомобиль: двигатель = {Engine}, сидений = {Seats}, GPS = {HasGPS}";
}
}
// Интерфейс строителя
public interface ICarBuilder
{
void Reset();
void SetEngine(string engine);
void SetSeats(int number);
void SetGPS(bool hasGPS);
Car GetResult();
}
// Конкретный строитель
public class CarBuilder : ICarBuilder
{
private Car _car = new Car();
public void Reset() => _car = new Car();
public void SetEngine(string engine) => _car.Engine = engine;
public void SetSeats(int number) => _car.Seats = number;
public void SetGPS(bool hasGPS) => _car.HasGPS = hasGPS;
public Car GetResult() => _car;
}
// Директор
public class Director
{
public void ConstructSportsCar(ICarBuilder builder)
{
builder.Reset();
builder.SetEngine("V8");
builder.SetSeats(2);
builder.SetGPS(true);
}
public void ConstructCityCar(ICarBuilder builder)
{
builder.Reset();
builder.SetEngine("V4");
builder.SetSeats(4);
builder.SetGPS(false);
}
}
// Использование
class Program
{
static void Main()
{
var director = new Director();
var builder = new CarBuilder();
director.ConstructSportsCar(builder);
Car sportsCar = builder.GetResult();
Console.WriteLine(sportsCar);
director.ConstructCityCar(builder);
Car cityCar = builder.GetResult();
Console.WriteLine(cityCar);
}
}
type Car struct {
Engine string
Seats int
HasGPS bool
}
func (c Car) String() string {
return fmt.Sprintf("Автомобиль: двигатель = %s, сидений = %d, GPS = %t", c.Engine, c.Seats, c.HasGPS)
}
type CarBuilder interface {
Reset()
SetEngine(engine string)
SetSeats(number int)
SetGPS(hasGPS bool)
Result() Car
}
type carBuilder struct {
car Car
}
func (b *carBuilder) Reset() { b.car = Car{} }
func (b *carBuilder) SetEngine(engine string) { b.car.Engine = engine }
func (b *carBuilder) SetSeats(number int) { b.car.Seats = number }
func (b *carBuilder) SetGPS(hasGPS bool) { b.car.HasGPS = hasGPS }
func (b *carBuilder) Result() Car { return b.car }
type Director struct{}
func (Director) ConstructSportsCar(b CarBuilder) {
b.Reset()
b.SetEngine("V8")
b.SetSeats(2)
b.SetGPS(true)
}
func (Director) ConstructCityCar(b CarBuilder) {
b.Reset()
b.SetEngine("V4")
b.SetSeats(4)
b.SetGPS(false)
}
func main() {
director := Director{}
builder := &carBuilder{}
director.ConstructSportsCar(builder)
fmt.Println(builder.Result())
director.ConstructCityCar(builder)
fmt.Println(builder.Result())
}
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class Car:
engine: str = ""
seats: int = 0
has_gps: bool = False
def __str__(self) -> str:
return f"Автомобиль: двигатель = {self.engine}, сидений = {self.seats}, GPS = {self.has_gps}"
class CarBuilder(ABC):
@abstractmethod
def reset(self) -> None: ...
@abstractmethod
def set_engine(self, engine: str) -> None: ...
@abstractmethod
def set_seats(self, number: int) -> None: ...
@abstractmethod
def set_gps(self, has_gps: bool) -> None: ...
@abstractmethod
def result(self) -> Car: ...
class SimpleCarBuilder(CarBuilder):
def __init__(self) -> None:
self.reset()
def reset(self) -> None:
self._car = Car()
def set_engine(self, engine: str) -> None:
self._car.engine = engine
def set_seats(self, number: int) -> None:
self._car.seats = number
def set_gps(self, has_gps: bool) -> None:
self._car.has_gps = has_gps
def result(self) -> Car:
return self._car
class Director:
def construct_sports_car(self, builder: CarBuilder) -> None:
builder.reset()
builder.set_engine("V8")
builder.set_seats(2)
builder.set_gps(True)
def construct_city_car(self, builder: CarBuilder) -> None:
builder.reset()
builder.set_engine("V4")
builder.set_seats(4)
builder.set_gps(False)
director = Director()
builder = SimpleCarBuilder()
director.construct_sports_car(builder)
print(builder.result())
director.construct_city_car(builder)
print(builder.result())
class Car {
engine = "";
seats = 0;
hasGPS = false;
toString(): string {
return `Автомобиль: двигатель = ${this.engine}, сидений = ${this.seats}, GPS = ${this.hasGPS}`;
}
}
interface CarBuilder {
reset(): void;
setEngine(engine: string): void;
setSeats(number: number): void;
setGPS(hasGPS: boolean): void;
getResult(): Car;
}
class SimpleCarBuilder implements CarBuilder {
private car = new Car();
reset(): void {
this.car = new Car();
}
setEngine(engine: string): void {
this.car.engine = engine;
}
setSeats(number: number): void {
this.car.seats = number;
}
setGPS(hasGPS: boolean): void {
this.car.hasGPS = hasGPS;
}
getResult(): Car {
return this.car;
}
}
class Director {
constructSportsCar(builder: CarBuilder): void {
builder.reset();
builder.setEngine("V8");
builder.setSeats(2);
builder.setGPS(true);
}
constructCityCar(builder: CarBuilder): void {
builder.reset();
builder.setEngine("V4");
builder.setSeats(4);
builder.setGPS(false);
}
}
const director = new Director();
const builder = new SimpleCarBuilder();
director.constructSportsCar(builder);
console.log(String(builder.getResult()));
director.constructCityCar(builder);
console.log(String(builder.getResult()));
class Car {
String engine;
int seats;
boolean hasGPS;
@Override
public String toString() {
return "Автомобиль: двигатель = " + engine + ", сидений = " + seats + ", GPS = " + hasGPS;
}
}
interface CarBuilder {
void reset();
void setEngine(String engine);
void setSeats(int number);
void setGPS(boolean hasGPS);
Car getResult();
}
class SimpleCarBuilder implements CarBuilder {
private Car car = new Car();
public void reset() {
car = new Car();
}
public void setEngine(String engine) {
car.engine = engine;
}
public void setSeats(int number) {
car.seats = number;
}
public void setGPS(boolean hasGPS) {
car.hasGPS = hasGPS;
}
public Car getResult() {
return car;
}
}
class Director {
void constructSportsCar(CarBuilder builder) {
builder.reset();
builder.setEngine("V8");
builder.setSeats(2);
builder.setGPS(true);
}
void constructCityCar(CarBuilder builder) {
builder.reset();
builder.setEngine("V4");
builder.setSeats(4);
builder.setGPS(false);
}
}
public class Program {
public static void main(String[] args) {
Director director = new Director();
CarBuilder builder = new SimpleCarBuilder();
director.constructSportsCar(builder);
System.out.println(builder.getResult());
director.constructCityCar(builder);
System.out.println(builder.getResult());
}
}
data class Car(
var engine: String = "",
var seats: Int = 0,
var hasGPS: Boolean = false,
) {
override fun toString() = "Автомобиль: двигатель = $engine, сидений = $seats, GPS = $hasGPS"
}
interface CarBuilder {
fun reset()
fun setEngine(engine: String)
fun setSeats(number: Int)
fun setGPS(hasGPS: Boolean)
fun result(): Car
}
class SimpleCarBuilder : CarBuilder {
private var car = Car()
override fun reset() {
car = Car()
}
override fun setEngine(engine: String) {
car.engine = engine
}
override fun setSeats(number: Int) {
car.seats = number
}
override fun setGPS(hasGPS: Boolean) {
car.hasGPS = hasGPS
}
override fun result(): Car = car
}
class Director {
fun constructSportsCar(builder: CarBuilder) {
builder.reset()
builder.setEngine("V8")
builder.setSeats(2)
builder.setGPS(true)
}
fun constructCityCar(builder: CarBuilder) {
builder.reset()
builder.setEngine("V4")
builder.setSeats(4)
builder.setGPS(false)
}
}
fun main() {
val director = Director()
val builder = SimpleCarBuilder()
director.constructSportsCar(builder)
println(builder.result())
director.constructCityCar(builder)
println(builder.result())
}
Плюсы и минусы
| Плюсы | Минусы |
|---|---|
| Позволяет создавать сложные объекты пошагово | Усложняет код при простых структурах объектов |
| Изолирует код сборки от представления объекта | Может потребовать дополнительных классов-строителей |
| Позволяет использовать один и тот же процесс для разных объектов | Увеличивает объём кода из-за добавления директора |
Заключение
Builder полезен, когда объект имеет сложную структуру и множество параметров. Он делает процесс создания гибким и контролируемым, упрощая изменение шагов построения и добавление новых вариантов конфигурации.