介绍:
- 建造者模式又叫生成器模式,是一种对象构建模式,他可以将复杂对象的构建过程从该对象中提出来,将对象属性行为和对象的构建分离开来,使这个抽象过程的不同实现方法可以构建出不同状态的对象。
- 建造者模式是一步步构建对象,他允许用户通过指定复杂对象的类型和内容就能进行构建,用户无需知道细节。
- 使产品和建造产品的过程解耦。
建造者的4个角色:
- Product:产品,即要构建的对象。
- BaseBuilder:抽象建造者,定义了构建这个对象所需的接口方法,可以是抽象类和接口。
- ImplementBuilder:具体构造者,真正构建对象的类。
- Director:指挥者,一个使用Builder接口的对象,主要有两个作用,一是:隔离客户与对象的生产过程;二是:复杂控制产品的生产过程细节。
场景:
- 现在要建造房子,房子的类型有普通房子和高楼大厦。
- 房子的属性都一样或者相差不大,只是不同的类型的房子属性值会有区别,比如普通房子的地基只要3米,而高楼大厦要10米。
- 房子的构建过程非常复杂。
初始版本UML图及代码:
public class House {
//地基高度
private double basicHigh;
//墙的厚度
private double wallWidth;
//层数
private int floorNum;
//颜色
private String color;
//屋顶颜色
private String roofColor;
//屋顶材料
private String roofType;
//高度
private double high;
//宽度
private double width;
//长度
private double houseLong;
public House(double basicHigh, double wallWidth, int floorNum, String color,
String roofColor, String roofType, double high,
double width, double houseLong) {
this.basicHigh = basicHigh;
this.wallWidth = wallWidth;
this.floorNum = floorNum;
this.color = color;
this.roofColor = roofColor;
this.roofType = roofType;
this.high = high;
this.width = width;
this.houseLong = houseLong;
}
}
public class Client {
public House getHouse(){
House commonHouse = new House(3,0.5,3,
"red","red","塑料",10.5,5,20);
return commonHouse;
}
}
//分析:
//1. 调用方client端知道house创建的细节。
//2. 假如房子的种类有多种种,每种的属性值又不相同,如果要让客户端自行构建的话会很不友好。容易出错。
改进后的UML图及代码:
public class House {
//地基高度
private double basicHigh;
//墙的厚度
private double wallWidth;
//层数
private int floorNum;
//颜色
private String color;
//屋顶颜色
private String roofColor;
//屋顶材料
private String roofType;
//高度
private double high;
//宽度
private double width;
//长度
private double houseLong;
//各种get set方法。
}
public abstract class BaseBuilder {
protected House house = new House();
public abstract BaseBuilder buildBasic();
public abstract BaseBuilder buildWall();
public abstract BaseBuilder buildFloor();
public abstract BaseBuilder buildColor();
public abstract BaseBuilder buildRoofColor();
public abstract BaseBuilder buildRoofType();
public abstract BaseBuilder buildHigh();
public abstract BaseBuilder buildWidth();
public abstract BaseBuilder buildHouseLong();
public House getResult() {
return buildBasic().buildWall().buildFloor().buildColor().buildRoofColor().buildRoofType()
.buildHigh().buildWidth().buildHouseLong().house;
}
}
public class CommonHouseBuilder extends BaseBuilder {
@Override
public BaseBuilder buildBasic() {
house.setBasicHigh(3);
System.out.println("建造普通房子地基高度->"+house.getBasicHigh());
return this;
}
@Override
public BaseBuilder buildWall() {
house.setWallWidth(0.5);
System.out.println("建造普通房子墙厚度->"+house.getWallWidth());
return this;
}
@Override
public BaseBuilder buildFloor() {
house.setFloorNum(3);
System.out.println("建造普通房子层数->"+house.getFloorNum());
return this;
}
@Override
public BaseBuilder buildColor() {
house.setColor("red");
System.out.println("建造普通房子整体颜色->"+house.getColor());
return this;
}
@Override
public BaseBuilder buildRoofColor() {
house.setRoofColor("red");
System.out.println("建造普通房子屋顶颜色->"+house.getRoofColor());
return this;
}
@Override
public BaseBuilder buildRoofType() {
house.setRoofType("瓦");
System.out.println("建造普通房子屋顶材料->"+house.getRoofType());
return this;
}
@Override
public BaseBuilder buildHigh() {
house.setHigh(10.5);
System.out.println("建造普通房子高度->"+house.getHigh());
return this;
}
@Override
public BaseBuilder buildWidth() {
house.setWidth(6);
System.out.println("建造普通房子宽度->"+house.getWidth());
return this;
}
@Override
public BaseBuilder buildHouseLong() {
house.setHouseLong(12);
System.out.println("建造普通房子长度->"+house.getHouseLong());
return this;
}
}
public class HighHouseBuilder extends BaseBuilder{
@Override
public BaseBuilder buildBasic() {
house.setBasicHigh(8);
System.out.println("建造高楼大厦地基高度->"+house.getBasicHigh());
return this;
}
@Override
public BaseBuilder buildWall() {
house.setWallWidth(0.8);
System.out.println("建造高楼大厦墙厚度->"+house.getWallWidth());
return this;
}
@Override
public BaseBuilder buildFloor() {
house.setFloorNum(15);
System.out.println("建造高楼大厦层数->"+house.getFloorNum());
return this;
}
@Override
public BaseBuilder buildColor() {
house.setColor("red");
System.out.println("建造高楼大厦整体颜色->"+house.getColor());
return this;
}
@Override
public BaseBuilder buildRoofColor() {
house.setRoofColor("red");
System.out.println("建造高楼大厦屋顶颜色->"+house.getRoofColor());
return this;
}
@Override
public BaseBuilder buildRoofType() {
house.setRoofType("混凝土");
System.out.println("建造高楼大厦屋顶材料->"+house.getRoofType());
return this;
}
@Override
public BaseBuilder buildHigh() {
house.setHigh(56.6);
System.out.println("建造高楼大厦高度->"+house.getHigh());
return this;
}
@Override
public BaseBuilder buildWidth() {
house.setWidth(30);
System.out.println("建造高楼大厦宽度->"+house.getWidth());
return this;
}
@Override
public BaseBuilder buildHouseLong() {
house.setHouseLong(50);
System.out.println("建造高楼大厦长度->"+house.getHouseLong());
return this;
}
}
public class Director {
private BaseBuilder baseBuilder;
public Director(BaseBuilder baseBuilder) {
this.baseBuilder = baseBuilder;
}
public void setBaseBuilder(BaseBuilder baseBuilder) {
this.baseBuilder = baseBuilder;
}
public House buildHouse(){
return baseBuilder.getResult();
}
}
public class Client {
public static House getHouse(Director director){
return director.buildHouse();
}
public static void main(String[] args) {
Director director = new Director(new CommonHouseBuilder());
House commonHouse = getHouse(director);
System.out.println("==============================================================");
System.out.println("==============================================================");
System.out.println("==============================================================");
director.setBaseBuilder(new HighHouseBuilder());
House highHouse = getHouse(director);
}
}
//分析:
//1. 把产品House与他的构建过程解耦,并且提供一个指挥者。客户端无需知道房子的具体构建细节,只需知道什么样的建造者会建造出什么样的房子即可。如果新增中房子,只需要新增一个建造者就可以,十分方便,符合开闭原则。
建造者模式的注意事项和细节:
- 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品。
- 每一个具体的建造者都是相对独立的,而与其他的建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的建造者即可得到不同的产品对象。
- 可以更加精细地控制产品的创建过程,将复杂产品的创建步骤分解在不同方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。粒度更细。
- 增加新的具体建造者无需修改原有类库代码。指挥者类针对抽象建造者编程,系统扩展方便,符合开闭原则。
- 建造者模式所创建的产品一般具有较多共同点,其组成部分相似,如果产品之间差异性很大,则不适合使用建造者模式,因此其范围受到一定的限制。
- 如果产品内部变化复杂,可能会导致需要定义很多具体建造者来实现会导致系统变得很庞大时,要考虑是否应该使用该模式。
抽象工厂模式VS建造者模式:
抽象工厂模式实现对产品族的创建,一个产品族是这样的一系列产品,具有不同的分类维度和产品组合,采用抽象工厂模式无需关系创建过程。只需关心什么产品由什么工厂生产。而建造者模式要求按照指定的蓝图建造产品,他的主要目的是通过组装零配件而产生一个新产品。
抽象工厂是不同产品不同工厂,建造者模式是同一产品不同建造模式不同建造者。