名称
生成器模式(BUILDER)
目的
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
适用性
在以下情况使用Builder模式
当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
当构造过程必须允许被构造的对象有不同的表示时。
结构
生成器(Builde):为创建一个product对象的各个部件指定抽象接口。
具体生成器(ConcreteBuilder):
实现Builder的接口以构造和装配该产品的各个部件。
定义并明确它所创建的表示。
提供一个检索产品的接口(例如,GetResult)。
导向器(Director):构造一个使用Builder接口的对象
产品(Product):
表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
协作
客户创建Director对象,并用它所想要的Builder对象进行配置。
一旦产品部件被生成,导向器就会通知生成器。
生成器处理导向器的请求,并将部件添加到该产品中。
客户从生成器中检索产品。
交互图如下:
注意:在java语言中,生成器可以是接口,也可以是抽象类,甚至是普通类,如果最后一步GetResult()要直接从抽象生成器上获取,那么就写成抽象类或者普通类,然后直接在抽象内中返回;如果要通过抽象生成器再到具体生成器中获取,那就写成接口,此时Product放在具体生成器中,接口中和实现类中都有GetResult()。无论哪种方式,抽象接口类中都有方法GetResult(),这点与结构图中有些差异。除非Construct()方法返回的是具体生成器,如果这样就会有两个Construct()方法。
效果
优点
它可以改变一个产品的内部表示。Builder对象提供给导向器一个构造产品的抽象接口,在改变该产品的内部表示时所要做的只是定义一个新的生成器。
它将构造代码和表示代码分开。Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个ConcreteBuilder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。
它可以对构造过程进行更精细的控制。Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。
缺点
增加系统复杂度。生成器模式引入了多个类(生成器类、具体生成器类、导向器类等),这会增加系统的复杂度,特别是对于简单对象来说,可能显得过于复杂。
产品必须有共同点。生成器模式适用于那些具有相同构建步骤的产品。如果产品的内部结构差异很大,则难以应用生成器模式。
可能违反开闭原则。如果需要添加新的产品特性或变种,可能需要修改现有的生成器类,这违反了开闭原则(Open/Closed Principle),即软件实体应该是对扩展开放的,对修改关闭的。
应用
问题
当我们组装电脑的时候,会有个电脑的组装顺序,我们需要知道电脑的组装过程和组装结果,这一点就和生成器模式非常类似。组装电脑时,组装电脑就是抽象生成器,组装戴尔还是苹果电脑就是具体生成器,谁来组装谁就是导向器(指挥者),抽象生成器定义各个步骤的组装方法,不同品牌的电脑在组装是会有不同的组装方法,导向器决定组装顺序并生成最后的组装结果。
示例
UML
代码示例
生成器:电脑生成器接口,定义了组装电脑的方法,同时还定义了一个获取结果的方法getComputer、一个Computer 对象
package com.ysj.part3.builder.builder;
import com.ysj.part3.builder.product.Computer;
public interface ComputerBuilder {
public Computer computer = new Computer();
/**
* 构建CPU
*/
void buildCpu();
/**
* 构建主板
*/
void buildBoard();
/**
* 构建显卡
*/
void buildCard();
/**
* 构建风扇
*/
void buildFan();
/**
* 构建内存
*/
void buildMemory();
/**
* 获取产品
*
* @return
*/
Computer getComputer();
}
具体生成器:戴尔、苹果具体生成器,实现抽象生成器ComputerBuilder
package com.ysj.part3.builder.concreteBuilder;
import com.ysj.part3.builder.builder.ComputerBuilder;
import com.ysj.part3.builder.product.Computer;
public class ConcreteDellBuilder implements ComputerBuilder {
@Override
public void buildCpu() {
System.out.println("构建戴尔CPU");
computer.setCpu("戴尔 CPU");
}
@Override
public void buildBoard() {
System.out.println("构建戴尔主板");
computer.setBoard("戴尔主板");
}
@Override
public void buildCard() {
System.out.println("构建戴尔显卡");
computer.setCard("戴尔显卡");
}
@Override
public void buildFan() {
System.out.println("构建戴尔风扇");
computer.setFan("戴尔风扇");
}
@Override
public void buildMemory() {
System.out.println("构建戴尔内存");
computer.setMemory("戴尔内存");
}
@Override
public Computer getComputer() {
return computer;
}
}
package com.ysj.part3.builder.concreteBuilder;
import com.ysj.part3.builder.builder.ComputerBuilder;
import com.ysj.part3.builder.product.Computer;
public class ConcreteMacBuilder implements ComputerBuilder {
@Override
public void buildCpu() {
System.out.println("构建MAC CPU");
computer.setCpu("MAC CPU");
}
@Override
public void buildBoard() {
System.out.println("构建MAC 主板");
computer.setBoard("MAC 主板");
}
@Override
public void buildCard() {
System.out.println("构建MAC 显卡");
computer.setCard("MAC 显卡");
}
@Override
public void buildFan() {
System.out.println("构建MAC 风扇");
computer.setFan("MAC 风扇");
}
@Override
public void buildMemory() {
System.out.println("构建MAC 内存");
computer.setMemory("MAC 内存");
}
@Override
public Computer getComputer() {
return computer;
}
}
导向器:组装电脑的人,声明了一个抽象生成器对象computerBuilder,定义了构建方法并返回computerBuilder(也可以返回Computer,随意)
@AllArgsConstructor
public class ComputerDirector {
private ComputerBuilder computerBuilder;
/**
* 以怎样的顺序构建ComputerBuilder,交给指挥者方法
* 动态指定构建流程
*/
public ComputerBuilder constructComputer(){
computerBuilder.buildBoard();
computerBuilder.buildCard();
computerBuilder.buildCpu();
computerBuilder.buildFan();
computerBuilder.buildMemory();
return computerBuilder;
}
}
产品:电脑,内部cpu等字段为需要构建的内容
package com.ysj.part3.builder.product;
import lombok.Data;
@Data
public class Computer {
//cpu
private String cpu;
//主板
private String board;
//显卡sasa
private String card;
//风扇
private String fan;
//内存
private String memory;
}
客户端:程序入口,最终调用者
package com.ysj.part3.builder;
import com.ysj.part3.builder.builder.ComputerBuilder;
import com.ysj.part3.builder.concreteBuilder.ConcreteDellBuilder;
import com.ysj.part3.builder.concreteBuilder.ConcreteMacBuilder;
import com.ysj.part3.builder.director.ComputerDirector;
import com.ysj.part3.builder.product.Computer;
/**
* 建造者模式
* 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
* 参考博客:https://blog.csdn.net/javanbme/article/details/116090368
*/
public class Client {
public static void main(String[] args) {
// 客户创建Director对象,并用它所想要的Builder对象进行配置
ComputerDirector computerDirector = new ComputerDirector(new ConcreteDellBuilder());
/*
* 一旦产品部件被生成,导向器就会通知生成器。
* 生成器处理导向器的请求,并将部件添加到该产品中。(以上步骤方法内部查看)
* 客户从生成器中检索产品。(getComputer方法)
*/
Computer computer = computerDirector.constructComputer().getComputer();
System.out.println(computer.toString());
}
}
已知应用
java 中的 Stream 框架
在 Java 8 引入的 Stream 框架中,就体现了生成器模式的思想。例如,通过 Stream.of() 方法可以创建一个流,然后可以使用一系列的中间操作和终端操作来生成和处理数据。
评论区