在软件开发过程中有时需要创建一个复杂的对象,这个复杂对象通常由多个子部件按一定的步骤组合而成。例如,计算机是由 OPU、主板、内存、硬盘、显卡、机箱、显示器、键盘、鼠标等部件组装而成的,采购员不可能自己去组装计算机,而是将计算机的配置要求告诉计算机销售公司,计算机销售公司安排技术人员去组装计算机,然后再交给要买计算机的采购员。
生活中这样的例子很多,如游戏中的不同角色,其性别、个性、能力、脸型、体型、服装、发型等特性都有所差异;还有汽车中的方向盘、发动机、车架、轮胎等部件也多种多样;每封电子邮件的发件人、收件人、主题、内容、附件等内容也各不相同。
以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。
建造者模式的定义与特点
建造者(Builder
)模式的定义:
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式
。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
该模式的主要优点如下:
1.各个具体的建造者相互独立,有利于系统的扩展。
2.客户端不必知道产品内部组成的细节,便于控制细节风险。
其缺点如下:
1.产品的组成部分必须相同,这限制了其使用范围。
2.如果产品的内部变化复杂,该模式会增加很多的建造者类。
建造者模式的结构
建造者(Builder
)模式由产品
、抽象建造者
、具体建造者
、指挥者
等 4 个要素构成,如下:
1.产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。
2.抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 。
3.具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
4.指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。
建造者模式的实现
用建造者(Builder)模式描述手机:
对照上边抽象工厂模式的结构:
1.产品角色(Phone ):包含多个组成部件的复杂对象
/**
* 产品:手机
* 使用lombok插件省去get,set,toString。
*/
@Date
public class Phone {
private String screen;//屏幕
private String shell;//外壳
private String cpu;//处理器
}
2.抽象建造者(AbstractWorker ):包含创建产品各个子部件的抽象方法的接口
/**
* 抽象建造者:造手机的工人
*/
public interface AbstractWorker {
AbstractWorker buildScreen();//造屏幕
AbstractWorker buildShell();//造外壳
AbstractWorker buildCpu();//造处理器
Phone build();//组装产品
}
3.具体建造者:实现 AbstractWorker 接口
/**
* 具体建造者:造华为手机的工人
*/
public class HWWorker implements AbstractWorker {
private Phone hwPhone = new Phone();
public AbstractWorker buildScreen() {
hwPhone.setScreen("华为的屏幕");
return this;
}
public AbstractWorker buildShell() {
hwPhone.setShell("华为的外壳");
return this;
}
public AbstractWorker buildCpu() {
hwPhone.setCpu("华为的cpu");
return this;
}
public Phone build() {
return hwPhone;
}
}
/**
* 具体建造者:造小米手机的工人
*/
public class XMWorker implements AbstractWorker{
private Phone xmPhone = new Phone();
public AbstractWorker buildScreen() {
xmPhone.setScreen("小米的屏幕");
return this;
}
public AbstractWorker buildShell() {
xmPhone.setShell("小米的外壳");
return this;
}
public AbstractWorker buildCpu() {
xmPhone.setCpu("小米的cpu");
return this;
}
public Phone build() {
return xmPhone;
}
}
4.指挥者(Director):调用建造者对象中的部件构造与装配方法完成复杂对象的创建
/**
* 指挥者
*/
public class Director {
private AbstractWorker builder;
//构造方法:给我华为的工人就构造一个华为的指挥者
public Director(AbstractWorker builder) {
this.builder = builder;
}
//产品构建与组装方法:指挥工人干活
public Phone builder(){
return builder.buildScreen()
.buildShell()
.buildCpu()
.build();
}
}
5.测试类:
public class BuilderPatternTest {
@Test
public void test(){
showPhone(new HWWorker());
showPhone(new XMWorker());
}
private void showPhone(AbstractWorker builder){
Director director = new Director(builder);//根据传入的工人构建不同的指挥者
Phone phone = director.builder();//指挥工人干活:造手机
System.out.println(phone);
}
}
6.测试结果:
华为的工人造华为的手机,小米的工人造小米手机
类结构图:
应用场景
建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用:
1.创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
2.创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
建造者模式和工厂模式的区别
1.建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。
2.创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的都一样。
3.关注的重点不同,工厂模式只需要把对象创建出来,而建造者不仅要创建出来,还要知道这个对象由哪些部件组成。
4.建造者模式根据建造过程中的顺序不一样,最终的对象部件组成也不一样。
建造者模式的扩展
建造者(Builder)模式在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。比如:
/**
* 产品:电脑
*/
public class Computer {
private String screen;//屏幕
private String shell;//外壳
private String cpu;//处理器
/**
* 造电脑的工人
*/
public class Worker {
private Computer computer = new Computer();
public Worker buildScreen(String screen) {
computer.setScreen(screen);
return this;
}
public Worker buildShell(String shell) {
computer.setShell(shell);
return this;
}
public Worker buildCpu(String cpu) {
computer.setCpu(cpu);
return this;
}
public Computer build() {
return computer;
}
}
//测试代码
@Test
public void test2 (){
Computer computer = new Worker().buildScreen("4K屏幕")
.buildShell("坚硬的外壳")
.buildCpu("高端处理器")
.build();
System.out.println(computer);
}
运行结果:
上面的示例代码只是传入三个参数,如果构造这个对象要13个参数呢,更多的参数呢,builder 模式的优势将会更加明显,传递参数更加灵活,代码具有更高的可读性。