文章目录
一、简介
1.1 引入
在现实世界中,一个对象往往是由多个对象或多个步骤去完成,比如:购买披萨的过程,在购买披萨的过程中可能会有不同的流程
- 首先将披萨制作完成,然后把大块披萨切成小块,最后打包
- 首先将披萨制作完成,然后先打包,回家后自己切披萨
- 首先将披萨制作完成,如果是小块披萨,就不用切分,直接打包回家
不同的客户有不同的需求,所以我们不能在构造方法中死板的、一次性的去满足不同用户的需求,而是要将披萨的购买过程分成若干个步骤,并将披萨的购买过程封装在另一个类中
1.2 定义
建造者模式:建造者模式又叫生成器模式,它是指将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式
- 它将一个复杂的对象分解成多个对象,然后再将分解的对象重新组建
1.3 建造者模式和工厂模式的区别
- 工厂模式注重的是产品的创建,不关心产品的组成部分,只要把产品生产出来即可
- 建造者模式也会创建产品,但是建造者模式不仅要创建产品,还需要关心这个产品的组成细节和过程。每一个组成细节对应一个方法,这些方法的不同执行顺序会得到该对象的不同表示
- 工厂模式只需要买到披萨即可,建造者模式不仅要买到披萨,还注重买披萨的过程。也就是说工厂模式注重结果,建造者模式注重细节
二、模式原理
2.1 模式组成
组成(角色) | 作用 |
---|---|
Builder(抽象建造者) | 它是一个包含创建产品各个子部件的抽象方法的接口。通常还包含一个用于返回Product的方法getProduct() |
ConcreteBuilder(具体建造者) | 实现Builder接口的类,实现各个部件的具体构造 |
Product(产品) | 它是具体建造者要构造的复杂对象,包含了产品的多个组成部件 |
Director(指挥者) | 该类需要含有一个Builder接口声明的变量,通过调用builder的getProduct()方法实现不同的创建顺序 |
2.2 UML类图
2.3 组成代码
- Product类:包含多个组成部件
public class Product{
private String part1;
private String part2;
private String part3;//这里的部件可以是任意类型
//省略了部件part1,2,3的getter()和setter()方法
}
- Builder接口:包含创建产品各个子部件的抽象方法
public interface Builder{
void buildPart1();
void buildPart2();
void buildPart3();
Product getProduct();
}
- ConcreteBuilder:实现了Builder中的抽象方法
public class ConcreteBuilder implements Builder{
private Product product;
//Product聚合到ConcreteBuilder中
public ConcreteBuilder(){
product = new Product();
}
public void buildPart1(){
System.out.println("完成部件1");
}
public void buildPart2(){
System.out.println("完成部件2");
}
public void buildPart3(){
System.out.println("完成部件3");
}
public Product getProduct(){
//不同具体建造者的getProduct()方法中有不同的调用顺序
buildPart1();
buildPart2();
buildPart3();
return product;
}
}
- Director:完成复杂对象的创建
public class Director{
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public Product construct(){
//不同的具体建造者得到该对象的不同表示
return builder.getProduct();
}
}
三、实例
3.1 实例概况
- 用户购买披萨,不同的用户可能有不同的购买流程
- 利用建造者模式来实现不同用户的购买流程
3.2 步骤
- Builder建造者:创建PizzaBuilder抽象建造者
//买披萨的流程
public interface PizzaBuilder {
void buildPart1();
void buildPart2();
void buildPart3();
Pizza getProduct();
}
- ConcreteProcess具体建造者:创建两个不同的具体建造流程
//根据流程1来完成:按照 制作-切片-打包
public class ConcreteProcessA implements PizzaBuilder{
private Pizza product;
public ConcreteProcessA() {
product = new Pizza();
}
public void buildPart1() {
System.out.println("完成制作");
}
public void buildPart2() {
System.out.println("完成切片");
}
public void buildPart3() {
System.out.println("完成打包");
}
public Pizza getProduct() {
System.out.println("根据流程1来完成:按照 制作-切片-打包");
buildPart1();
buildPart2();
buildPart3();
return product;
}
}
//根据流程2来完成:按照 制作-打包-切片
public class ConcreteProcessB implements PizzaBuilder{
private Pizza product;
public ConcreteProcessB() {
product = new Pizza();
}
public void buildPart1() {
System.out.println("完成制作");
}
public void buildPart2() {
System.out.println("完成切片");
}
public void buildPart3() {
System.out.println("完成打包");
}
public Pizza getProduct() {
System.out.println("根据流程2来完成:按照 制作-打包-切片");
buildPart1();
buildPart3();
buildPart2();
return product;
}
}
- Product产品:创建Pizza产品类
//根据流程2来完成:按照 制作-打包-切片
public class ConcreteProcessB implements PizzaBuilder{
private Pizza product;
public ConcreteProcessB() {
product = new Pizza();
}
public void buildPart1() {
System.out.println("完成制作");
}
public void buildPart2() {
System.out.println("完成切片");
}
public void buildPart3() {
System.out.println("完成打包");
}
public Pizza getProduct() {
System.out.println("根据流程2来完成:按照 制作-打包-切片");
buildPart1();
buildPart3();
buildPart2();
return product;
}
}
- Director指挥者:创建指挥者
//指挥者,根据不同具体创建者实现产品的生产
public class Director {
private PizzaBuilder builder;
public Director(PizzaBuilder builder) {
this.builder = builder;
}
//返回产品pizza
public Pizza construct() {
return builder.getProduct();
}
}
- 外部调用,走不同的流程购买pizza
public class Client {
public static void main(String[] args) {
//根据流程1来完成:按照 制作-切片-打包
//具体创建者
PizzaBuilder builder = new ConcreteProcessA();
//指挥者
Director director = new Director(builder);
//指挥者调用construct方法,根据 不同的具体创建者 创建产品
Pizza product = director.construct();
System.out.println("-------------");
//根据流程2来完成:按照 制作-打包-切片
builder = new ConcreteProcessB();
director = new Director(builder);
product = director.construct();
}
}
//输出结果
根据流程1来完成:按照 制作-切片-打包
完成制作
完成切片
完成打包
-------------
根据流程2来完成:按照 制作-打包-切片
完成制作
完成打包
完成切片
3.3 UML类图
四、优缺点
4.1 优点
- 建造者模式将对象的构造过程封装在具体建造者中,不同的具体建造者可以得到该对象的不同表示
- 不同的具体建造者之间相互独立,可以比较方便的替换具体建造者或增加新的具体建造者
- 可以更加精细有效的控制对象的构造过程。将复杂产品的创建步骤分解到不同的方法中,使得创建过程更加精细
- 增加新的具体建造者时,不需要修改指挥者的代码,满足"开闭原则"
4.2 缺点
- 建造者模式创建的产品,他们的组成部分相似,如果产品之间的差异性很大,就不适合使用建造者模式
- 如果产品的内部变化较大,那么Builder和ConcreteBuilder也要同步修改,维护成本较大
五、应用场景
建造者模式主要是针对复杂对象的创建,如果创建简单对象的话通常使用工厂模式进行创建。两者可以结合使用
建造者模式主要适用于以下应用场景:
- 相同的方法,不同的执行顺序,产生不同的结果
- 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同
- 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用
- 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值