工厂模式和建造者模式都是创建型模式,说白了都是为了创建对象为目标用途的设计模式。肯定会拿来比较,一般来说肯定是工厂模式更易懂,使用在平时的项目中更顺手。而建造者模式,更多是创建一个对象,要给这个对象给定一些参数来。有时候甚至感觉传统的建造者模式,有时候特别像工厂模式,因为有时候我们会给建造者抽象类定义几个“模板”,这几个模板特别像工厂模式里面的。所以有时候有点二者区分不开。
这里我们首先看一下基本的传统的建造者模式的结构:
这里面我有一个建造者模式的demo:
建造者模式demo
大体上我们可以区分为四部分:
- Product: 最终要生成的对象,例如 Computer实例。
- Builder:
构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product
getProduct()。 - ConcreteBuilder: Builder的实现类。
- Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder
builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的
getProduct() 方法获得最终的产品。
实际上在我们实现Builder基类时,实现了几个不同的ConcreateBuilder,实际上我认为时将工厂模式融合到里面了,为什么这样认为。我后面会说。
但是这种方式特别像我们常看到的一些比较肤浅的关于设计模式的文章,我们通过去记结构去记名字,实际上区分不出来什么,因为设计模式很多结构差不多,而且实际中最佳范例或者源码里面也不会标出这些,命名不规范这些。
尽信书不如无书。
实际上建造模式我认为最好的方式是内部类这种。
关于常规的建造者模式的内部类改造
对比工厂模式和建造者模式
相同点:创建型设计模式,目的相同,创建对象
不同点:工厂模式时是制式创建设计模式,哪怕你有一百个实现类,创建出来也就一百个类型。建造者模式,是自定义的模式,也许我就一个实现类ConcreateBuilder,但是里面参数我自己往里面塞,我可以理论上有无数种类型的。(通俗一点说,一个时制式化,一个是客制化)。
最后是一个我改写的内部类建造者模式demo。你可以尝试看看,传统的四部分是怎么在内部类改造中体现的,以及对比和传统的建造者模式的优势。
package com.example.test.builder.innerClass;
/**
* @Author: zhangpeng
* @Description:
* @Date: 2022/10/8
*/
public class InnerComputerBuilder {
private String cpu;//必须
private String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选
public static class Builder{
//必须
private String cpu;
private String ram;
//可选
private int usbCount;
private String keyboard;
private String display;
public Builder( String cpu,String ram){
this.cpu = cpu;
this.ram = ram;
}
public Builder usbCount(int usbCount){
this.usbCount = usbCount;
return this;
}
public Builder keyBoard(String keyboard){
this.keyboard = keyboard;
return this;
}
public Builder display(String display){
this.display = display;
return this;
}
public InnerComputerBuilder build(){
return new InnerComputerBuilder(this);
}
}
private InnerComputerBuilder(Builder builder){
cpu = builder.cpu;
ram = builder.ram;
usbCount = builder.usbCount;
}
public static void main(String[] args) {
InnerComputerBuilder computerDirector = new InnerComputerBuilder.Builder("12400","16G").usbCount(3).keyBoard("84").display("24").build();
}
}