造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。
简单来说,假设我们需要装电脑主机,都是电脑但是配置可能不同,有的人光追,有的人想要AMD全家桶。那我们需要的就是创建电脑这个对象,他的构件过程,零件选择,都是不必要知道细节的,全部由我们该出的套餐来进行装机。
建造者模式一般有四个角色:
抽象创建者角色:
给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体创建者角色。具体创建者必须实现这个接口的两种方法:一是建造方法,另一种是结果返回方法。一般来说,产品所包含的零件数目与建造方法的数目相符。换言之,有多少零件,就有多少相应的建造方法。
具体创建者角色:
他们在应用程序中负责创建产品的实例。这个角色要完成的任务包括:
1、实现抽象创建者所声明的抽象方法,给出一步一步的完成产品创建实例的操作。
2、在创建完成后,提供产品的实例。
导演者角色:
这个类调用具体创建者角色以创建产品对象。但是导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体创建者角色。
产品角色:
产品便是建造中的复杂对象。一般说来,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以使不相关联的。
=========================================================================
我们模拟一个配电脑的场景:
我们设计有两个电脑套餐,一个AMD全家桶,一个游戏王者,我们根据用户的选择给出相应的配置单。
首先我们根据装机的原材料来抽象一个建造类接口,用于统一标准获取硬件信息。
原材料抽象类:
package BuilderPattern;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName AbstractComputerBuilder.java
* @Description 抽象建造类,提供创建产品的共同接口,不同的产品可以有自己的具体实现
硬件接口,统一标准获取硬件信息,生成装机配置单
* @createTime 2022年02月25日 15:18:00
*/
public interface AbstractComputerBuilder {
/**
* 硬件种类
* @return 硬件名
*/
String name();
/**
* 硬件品牌
* @return 品牌名
*/
String brand();
/**
* 制造商
* @return 制造商
*/
String manufacturer();
/**
* 型号
* @return 型号
*/
String model();
/**
* 价格
* @return 价格
*/
BigDecimal price(); // 价格
/**
* 描述
* @return 描述
*/
String desc();
}
然后我们考虑制造的原材料,也就是产品角色类。
我们假设有三类,CPU,GPU和SSD。
CPU:
amd cpu
package BuilderPattern.dao.CPU;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName AMD5800X.java
* @Description AMD5800X
* @createTime 2022年02月25日 15:45:00
*/
public class AMD5800X implements AbstractComputerBuilder {
@Override
public String name() {
return "CPU";
}
@Override
public String brand() {
return "AMD";
}
@Override
public String manufacturer() {
return "MediaTek";
}
@Override
public String model() {
return "5800X";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(2399);
}
@Override
public String desc() {
return "八核心十六线程,CPU主频:3.8GHz, 动态加速频率:4.7GHz";
}
}
Intel cpu
package BuilderPattern.dao.CPU;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Intel12700KF.java
* @Description AMD5800X
* @createTime 2022年02月25日 15:43:00
*/
public class Intel12700KF implements AbstractComputerBuilder {
@Override
public String name() {
return "CPU";
}
@Override
public String brand() {
return "Intel";
}
@Override
public String manufacturer() {
return "Intel";
}
@Override
public String model() {
return "12700KF";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(3199);
}
@Override
public String desc() {
return "十二核心二十线程, CPU主频:3.6GHz, 动态加速频率:4.9GHz";
}
}
=========================================================================
GPU:
AMD毒药
package BuilderPattern.dao.GPU;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Toxic.java
* @Description 毒药显卡
* @createTime 2022年02月25日 15:39:00
*/
public class Toxic implements AbstractComputerBuilder {
@Override
public String name() {
return "Graphic Card";
}
@Override
public String brand() {
return "AMD";
}
@Override
public String manufacturer() {
return "Sapphire";
}
@Override
public String model() {
return "RX6900 XT";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(14999.00);
}
@Override
public String desc() {
return "核心频率: 2730MHz ,显存频率: 16800MHz, 显存容量: 16GB GDDR6X";
}
}
七彩虹火神
package BuilderPattern.dao.GPU;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Vulcan.java
* @Description 火神显卡
* @createTime 2022年02月25日 15:30:00
*/
public class Vulcan implements AbstractComputerBuilder {
@Override
public String name() {
return "Graphic Card";
}
@Override
public String brand() {
return "Nvidia";
}
@Override
public String manufacturer() {
return "Colorful";
}
@Override
public String model() {
return "GeForce RTX 3090";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(16999.99);
}
@Override
public String desc() {
return "核心频率: 1395-1860MHz,显存频率: 19500MHz, 显存容量: 24GB GDDR6X";
}
}
=========================================================================
SSD:
三星
package BuilderPattern.dao.memory;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Samsung980Pro.java
* @Description Samsung980Pro
* @createTime 2022年02月25日 15:51:00
*/
public class Vnand implements AbstractComputerBuilder {
@Override
public String name() {
return "Memory";
}
@Override
public String brand() {
return "Samsung";
}
@Override
public String manufacturer() {
return "Samsung";
}
@Override
public String model() {
return "980Pro";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(1399.00);
}
@Override
public String desc() {
return "1TB SSD PCIE4.0 M.2";
}
}
SN850
package BuilderPattern.dao.memory;
import BuilderPattern.AbstractComputerBuilder;
import java.math.BigDecimal;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName SN850.java
* @Description SN850
* @createTime 2022年02月25日 15:55:00
*/
public class WdBlack implements AbstractComputerBuilder {
@Override
public String name() {
return "Memory";
}
@Override
public String brand() {
return "Western Digital";
}
@Override
public String manufacturer() {
return "SanDisk";
}
@Override
public String model() {
return "SN850";
}
@Override
public BigDecimal price() {
return BigDecimal.valueOf(1499.00);
}
@Override
public String desc() {
return "1T SSD PCIE4.0 M.2";
}
}
=========================================================================
然后根据以上的原材料,组装成不同的配置单
这时候我们就使用一个抽象创建者角色来实现创建配置单:
package BuilderPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Builder.java
* @Description 抽象创建者角色
* @createTime 2022年02月25日 16:48:00
*/
public interface ListBuilder {
//添加CPU信息
ListBuilder appendCpu(AbstractComputerBuilder abs);
//添加GPU信息
ListBuilder appendGpu(AbstractComputerBuilder abs);
//添加SSD信息
ListBuilder appendSSD(AbstractComputerBuilder abs);
//获取实例
String getDetail();
}
=========================================================================
使用具体创建者角色来实现抽象创建者,并返回配置单。
package BuilderPattern;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName ComputerList.java
* @Description 具体创建者角色
* @createTime 2022年02月25日 16:51:00
*/
public class ComputerList implements ListBuilder{
private List<AbstractComputerBuilder> computerList = new ArrayList<>();
private BigDecimal price = BigDecimal.ZERO;
private String level;
public ComputerList() {
}
public ComputerList(String level) {
this.level = level;
}
@Override
public ListBuilder appendCpu(AbstractComputerBuilder abs) {
computerList.add(abs);
price = price.add(abs.price());
return this;
}
@Override
public ListBuilder appendGpu(AbstractComputerBuilder abs) {
computerList.add(abs);
price = price.add(abs.price());
return this;
}
@Override
public ListBuilder appendSSD(AbstractComputerBuilder abs) {
computerList.add(abs);
price = price.add(abs.price());
return this;
}
@Override
public String getDetail() {
StringBuilder detail = new StringBuilder("\r\n============================================\r\n" +
"配置清单" + "\r\n" +
"电脑等级:" + level + "\r\n" +
"总价:" + price.setScale(2, RoundingMode.HALF_UP) + " 元\r\n" +
"配件清单:\r\n");
for (AbstractComputerBuilder abs:computerList) {
detail. append(abs.name()).append(": ").
append(abs.brand()).append(", ").
append(abs.model()).append(", ").
append(abs.manufacturer()).append(", ").
append(abs.desc()).append(", ").
append(abs.price()).append("\n");
}
return detail.toString();
}
}
=========================================================================
导演者角色创建产品对象。
package BuilderPattern;
import BuilderPattern.dao.CPU.AMD5800X;
import BuilderPattern.dao.CPU.Intel12700KF;
import BuilderPattern.dao.GPU.Toxic;
import BuilderPattern.dao.GPU.Vulcan;
import BuilderPattern.dao.memory.Vnand;
import BuilderPattern.dao.memory.WdBlack;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName Builder.java
* @Description 导演者角色
* @createTime 2022年02月25日 16:57:00
*/
public class Actor {
public ComputerList levelOne(String level){
return (ComputerList) new ComputerList(level).appendCpu(new AMD5800X()).appendGpu(new Toxic()).appendSSD(new WdBlack());
}
public ComputerList levelTwo(String level){
return (ComputerList) new ComputerList(level).appendCpu(new Intel12700KF()).appendGpu(new Vulcan()).appendSSD(new Vnand());
}
}
这样就实现了使用建造者模式创造一个配置单。
=========================================================================
测试一下:
用户只用告诉我们他想要游戏王者还是AMD全家桶,我们就可以给他对应的配置单,用户不需要了解内部具体的创建过程。
package BuilderPattern;
/**
* @author Zeyu Wan
* @version 1.0.0
* @ClassName ComputerListTest.java
* @Description 游戏配置单测试类
* @createTime 2022年02月25日 16:20:00
*/
public class ComputerListTest {
public static void main(String[] args) {
String level = "游戏王者";
getComputerList(level);
}
public static void getComputerList(String level){
/*
* 创建导演类和的建造者
*/
Actor actor = new Actor();
/*
* 利用导演类来获得单子
*/
if ("AMD全家桶".equals(level)) {
System.out.println(actor.levelOne(level).getDetail());
}else if ("游戏王者".equals(level)){
System.out.println(actor.levelTwo(level).getDetail());
}else {
System.out.println("选择错误");
}
}
}
=========================================================================
优点:
- 在建造者模式中, 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
缺点:
-
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
-
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。