Шаблон проектирования “Строитель”
Шаблон “Строитель” позволяет отделить конструирование сложного объекта от его представления. Таким образом, один и тот же процесс конструирования может создавать различные представления.
Шаблон проектирования “Строитель” второго типа
В реальном сценарии для того, чтобы создать компьютер, требуется использовать множество компонентов: оперативную память, процессор, вентиляторы и графическую карту.
Структура:
- Продукт — сложный объект, который мы хотим создать.
- Builder — абстрактный базовый класс, который определяет все шаги, необходимые для корректного создания продукта.
- Concrete Builder реализует интерфейс
Builder
.
Продукт: класс Computer
.
public class Computer {
private String Ram;
private String Cpu;
//геттер и сеттер
@Override
public String toString() {
return "Computer{" +
"Ram='" + Ram + '\'' +
", Cpu='" + Cpu + '\'' +
'}';
}
}
Класс Builder:
public abstract class Builder {
protected Computer computer = new Computer();
public abstract void buildRam();
public abstract void buildCpu();
public abstract Computer createComputer();
}
Конкретные классы Builder: AsusComputerBuilder
и AcerComputerBuilder
.
public class AcerComputerBuilder extends Builder{
@Override
public void buildRam() {
computer.setRam("(Acer) 8GB RAM");
}
@Override
public void buildCpu() {
computer.setCpu("(Acer) AMD CPU");
}
@Override
public Computer createComputer() {
return computer;
}
}
public class AsusComputerBuilder extends Builder{
@Override
public void buildRam() {
computer.setRam("(Asus) 16GB RAM");
}
@Override
public void buildCpu() {
computer.setCpu("(Asus) Intel CPU");
}
@Override
public Computer createComputer() {
return computer;
}
}
Класс Director:
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public Computer construct(){
builder.buildRam();
builder.buildCpu();
return builder.computer;
}
}
Применение:
public class Client {
public static void main(String[] args) {
Director director = new Director(new AsusComputerBuilder());
Computer computer = director.construct();
System.out.println(computer);//toString()
}
}
Output:
Computer{Ram='(Asus) 16GB RAM', Cpu='(Asus) Intel CPU'}
В данном случае абстрактный класс Computer
определил, какой компонент нужен, а абстрактный класс Builder
выявил метод для сборки компонента компьютера. После этого мы можем создавать различные типы компьютера в конкретном классе Builder, например AsusComputerBuilder
и AcerComputerBuilder
, и реализовывать метод, определенный абстрактным классом Builder
.
Для создания полноценного компьютера с помощью “Строителя” понадобится класс Director
, для чего схема применения направляется в конкретный Builder, который мы объявили в конструкторе Director
.
Шаблон проектирования “Строитель” второго типа
Когда конструктор класса требует много параметров, читаемость класса ухудшается, и в нем легко допустить опечатки. В этом случае для рефакторинга можно использовать шаблон “Строитель”.
До:
public class Computer {
private String cpu;
private String ram;
private String storage;
private String brand;
public Computer(String cpu, String ram, String storage, String brand) {
this.cpu = cpu;
this.ram = ram;
this.storage = storage;
this.brand = brand;
}
// геттер и сеттер
@Override
public String toString() {
return "Phone{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage='" + storage + '\'' +
", brand='" + brand + '\'' +
'}';
}
}
Применение:
public static void main(String[] args) {
Computer computer = new Computer("Intel","Kingston 8GB","WD SSD 500GB","Asus");
System.out.println(computer);
//Вывод: Phone{cpu='Intel', ram='Kingston 8GB', storage='WD SSD 500GB', brand='Asus'}
}
После:
public class Computer {
private String cpu;
private String ram;
private String storage;
private String brand;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ram = builder.ram;
this.storage = builder.storage;
this.brand = builder.brand;
}
public static final class Builder{
private String cpu;
private String ram;
private String storage;
private String brand;
public Builder cpu(String cpu){
this.cpu = cpu;
return this;//возврат Builder
}
public Builder ram(String ram){
this.ram = ram;
return this;
}
public Builder storage(String storage){
this.storage = storage;
return this;
}
public Builder brand(String brand){
this.brand = brand;
return this;
}
public Computer build(){
return new Computer(this);
}
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", storage='" + storage + '\'' +
", brand='" + brand + '\'' +
'}';
}
}
Применение:
public static void main(String[] args) {
Computer computer = new Computer.Builder() //создание класса Builder для вызова метода builder
.cpu("Intel") //установка данных cpu и возврат класса Builder с помощью ключевого слова "this"
.ram("Kingston 8GB")//ram можно вызвать после вызова метода cpu(), поскольку метод cpu() возвращает ключевое слово "this" класса Builder.
.storage("WD SSD 500GB")
.brand("Asus")
.build();//вызов метода build() для вызова частного конструктора Computer с целью создания объекта Computer
System.out.println(computer);//Computer{cpu='Intel', ram='Kingston 8GB', storage='WD SSD 500GB', brand='Asus'}
}
В данном случае мы модифицируем конструктор Computer
в модификатор с частным доступом. Затем, используя внутренний класс Builder
, собираем каждый компонент и вызываем метод build()
для создания объекта Computer
.
Читайте также:
- 23 шаблона проектирования для 99% разработчиков на Java
- 11 исходных программ JavaScript, предоставляющих шаблоны проектирования
- Антишаблоны программирования
Читайте нас в Telegram, VK и Дзен
Перевод статьи Lim Yee Jie: Understanding Design Pattern — Builder Pattern