一,简介
建造者模式也叫生成器模式作为创建型模式之一,有着广泛的应用,它一般用来创建复杂的对象,他将复杂的对象的构建与他的表示进行分离,使得同样的创建过程可以有不用的表示;通俗的来将就是,建造者模式将一个简单的对象一步步按不同的顺序封装为复杂的对象。
建造者模式解决的问题:将组件和组装过程分开,一步一步创建一个复杂的对象,用户只需要指定复杂对象的类型就可以得到该对象,而无需知道其内部的具体构造细节。
二、结构
由类图可以看出,建造者模式结构主要由产品类、抽象建造者、具体建造者和指挥着类构成
①抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建,由子类实现。
②具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
③产品类(Product):要创建的复杂对象。
④指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
三、优缺点
优点:
1.灵活:可以分步骤地构建复杂对象,使得构建过程更加灵活。
2.解耦:可以隔离复杂对象的创建和使用,客户端不必关心对象的创建细节。
3.易扩展:增加新的具体建造者很方便,可以扩展构建器功能,符合开闭原则。
缺点:1.增加工作量:需要额外的代码来创建和管理具体建造者类,增加了程序员的工作量。
2.效率低:相比于其他创建型模式,在运行时效率较低,特别是对象太复杂时。
四、代码实现
汽车有不同的品牌,比如我们要构造一辆简易的小汽车,他由轮子、发动机、底盘等构成,那么实现代码如下
1.产品类
/**
* 产品类:小汽车类
*/
public class Car {
//小汽车名字
private String name;
//轮胎
private String tire;
//底盘
private String chassis;
//发动机
private String engine;
//getter and setter
}
2.抽象建造者
/**
* 抽象构造者
*/
public abstract class CarBuilder {
//简易的小汽车
private Car car=new Car();
//返回小汽车
public Car getCar(String name){
car.setName(name);
return car;
}
//构建轮胎
public abstract void buildTire();
//构建底盘
public abstract void buildChassis();
//构建发动机
public abstract void buildEngine();
}
3.具体构造者
/**
* 具体构造者
*/
public class AoDiCarBuilder extends CarBuilder {
@Override
public void buildTire() {
System.out.println("奥迪专用轮胎");
}
@Override
public void buildChassis() {
System.out.println("奥迪专用底盘");
}
@Override
public void buildEngine() {
System.out.println("奥迪专用发动机");
}
@Override
public Car getCar(String name) {
return super.getCar(name);
}
}
/**
* 具体构造者
*/
public class BaoMaCarBuilder extends CarBuilder {
@Override
public void buildTire() {
System.out.println("宝马专用轮胎");
}
@Override
public void buildChassis() {
System.out.println("宝马专用底盘");
}
@Override
public void buildEngine() {
System.out.println("宝马专用发动机");
}
@Override
public Car getCar(String name) {
return super.getCar(name);
}
}
/**
* 具体构造者
*/
public class BenChiCarBuilder extends CarBuilder {
@Override
public void buildTire() {
System.out.println("奔驰专用轮胎");
}
@Override
public void buildChassis() {
System.out.println("奔驰专用底盘");
}
@Override
public void buildEngine() {
System.out.println("奔驰专用发动机");
}
@Override
public Car getCar(String name) {
return super.getCar(name);
}
}
4.指挥者
/**
* 指挥者
*/
public class Director {
private CarBuilder carBuilder;
public CarBuilder getCarBuilder() {
return carBuilder;
}
public void setCarBuilder(CarBuilder carBuilder) {
this.carBuilder = carBuilder;
}
public void makeCar() {
carBuilder.buildTire();
carBuilder.buildChassis();
carBuilder.buildEngine();
}
}
5.测试类
public class CarBuilderTest {
public static void main(String[] args) {
Director director = new Director();
director.setCarBuilder(new AoDiCarBuilder());
director.makeCar();
director.setCarBuilder(new BaoMaCarBuilder());
director.makeCar();
}
}
以上就是小汽车的制作过程简单实例,但是这样的编码方式不是很灵活,我们可以将其转换为链式调用,比如我们在web开发中,经常需要与前端进行对接,如果我们随机的返回数据,会导致代码结构非常的混乱,因此需要统一我们的返回值供前端获取,那么这个统一返回类结合建造者模式如何封装呢?
package com.dahai.create.build.result;
import java.util.Map;
/**
* 返回实体类,一般由code message data组成
*/
public class Result {
//返回编码
private Integer code;
//信息
private String message;
//返回数据
private Map<String, Object> data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
/**
* 结果构造者
*/
class ResultBuilder {
private Result result = new Result();
public ResultBuilder addCode(int code) {
result.setCode(code);
return this;
}
public ResultBuilder addMessage(String message) {
result.setMessage(message);
return this;
}
public ResultBuilder addData(Map<String,Object> data) {
result.setData(data);
return this;
}
public Result getResult() {
return result;
}
}
class ResultBuilderTest{
public static void main(String[] args) {
Result result = new ResultBuilder()
.addCode(-1)
.addMessage("参数错误")
.addData(null)
.getResult();
System.out.println("result = " + result);
}
}
五、应用场景
生活场景
盒饭套餐:顾客可以选择不同的菜,服务员按照顾客的要求,将这些菜组合起来,最终构建出一个完整的套餐。
盖房子:需要分多个阶段进行,比如准备材料、打地基、盖围墙...。建造者模式可以将房屋的建造分解成多个步骤,每个步骤对应一个具体的建造者,最终由包工头(指导者)来调用不同的建造者,完成整个房子的建造。
ava场景
StringBuilder:能够动态地构建字符串。
Stream API:将集合类转为stream流,通过一系列的中间操作和终止操作来生成最终结果。
Lombok的@Builder注解:一个注解就可以生成建造者模式的代码。
六、对比总结
6.1使用场景
当需要创建一些特定的对象,但是它们拥有共同的组成部分时,比如:一个房子可以由个个部件:框架、墙、窗户等,这些部件可以组合起来构造完整的房子。
当对象的构建过程比较复杂且需要多个步骤时,例如,创建一份电子商务订单需要多个步骤,如选择商品、填写地址和支付等,这些步骤可以被分别封装成为订单构建器中的不同方法。
当需要创建一些特定类型的对象,例如复杂的数据结构或配置对象时,这在编写配置文件解析器以及通用数据结构如二叉树等时很有用。
建造者模式也可以被用于通过更高级的方式来构建复杂对象,例如:序列化和反序列化。
6.2与抽象工厂模式的区别
抽象工厂模式强调的是产品族的创建,即相关的产品一起被创建出来,而建造者模式强调的是一个复杂对象的创建,即它的各个部分逐步被创建出来。