盖房子的需求:
1.建造房子的过程:打桩、砌墙、封顶
2.房子是多样的,有普通房、高楼、别墅等。虽然过程一样,但是要求是不同的
传统的方法:
问题:
设计的程序结构过于简单,并没有缓存层对象,致使程序的扩展和维护不好。产品和创建房子的过程封装在一起,耦合性较强。
建造者模式
又叫生成器模式(Builder)
它可以分步骤创建复杂对象,该模式允许你使用相同的创建代码生成不同类型和形式的对象。
建造者模式结构图
1.生成器 (Builder)
接口声明在所有类型生成器中通用的产品构造步骤。
2.具体生成器 (Concrete Builders)
提供构造过程的不同实现。 具体生成器也可以构造不遵循通用接口的产品。
3.产品 (Products)
是最终生成的对象。 由不同生成器构造的产品无需属于同一类层次结构或接口。
4.主管 (Director)
类定义调用构造步骤的顺序, 这样你就可以创建和复用特定的产品配置。
5.客户端 (Client)
必须将某个生成器对象与主管类关联。 一般情况下, 你只需通过主管类构造函数的参数进行一次性关联即可。 此后主管类就能使用生成器对象完成后续所有的构造任务。 但在客户端将生成器对象传递给主管类制造方法时还有另一种方式。 在这种情况下, 你在使用主管类生产产品时每次都可以使用不同的生成器。
建造者模式应用场景
1.使用生成器模式可避免 “重叠构造函数 (telescopic constructor)” 的出现。
2.当你希望使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用生成器模式。
3.使用生成器构造组合树或其他复杂对象
实现方法
1.清晰地定义通用步骤, 确保它们可以制造所有形式的产品。 否则你将无法进一步实施该模式。
2.在基本生成器接口中声明这些步骤。
3.为每个形式的产品创建具体生成器类, 并实现其构造步骤。
不要忘记实现获取构造结果对象的方法。 你不能在生成器接口中声明该方法, 因为不同生成器构造的产品可能没有公共接口, 因此你就不知道该方法返回的对象类型。 但是, 如果所有产品都位于单一类层次中, 你就可以安全地在基本接口中添加获取生成对象的方法。
4.考虑创建主管类。 它可以使用同一生成器对象来封装多种构造产品的方式。
5.客户端代码会同时创建生成器和主管对象。 构造开始前, 客户端必须将生成器对象传递给主管对象。 通常情况下, 客户端只需调用主管类构造函数一次即可。 主管类使用生成器对象完成后续所有制造任务。 还有另一种方式, 那就是客户端可以将生成器对象直接传递给主管类的制造方法。
6.只有在所有产品都遵循相同接口的情况下, 构造结果可以直接通过主管类获取。 否则, 客户端应当通过生成器获取构造结果。
生成器模式优缺点
优点:
✔️你可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。
✔️生成不同形式的产品时, 你可以复用相同的制造代码。
✔️单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。
缺点:
❌ 由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加。
更改后的盖房子项目
代码:
public class House {
private String baise;
private String wall;
private String roofed;
public String getBaise() {
return baise;
}
public void setBaise(String baise) {
this.baise = baise;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoofed() {
return roofed;
}
public void setRoofed(String roofed) {
this.roofed = roofed;
}
}
public abstract class HouseBuilder {
protected House house = new House();
//将建造的流程写好
public abstract void buildBasic();
public abstract void buildWalls();
public abstract void roofed();
public House buildHouse(){
return house;
}
}
public class CommonHouse extends HouseBuilder {
@Override
public void buildBasic() {
System.out.println("普通房子打地基");
}
@Override
public void buildWalls() {
System.out.println("普通房子砌墙");
}
@Override
public void roofed() {
System.out.println("普通房子封顶");
}
}
public class HighHouse extends HouseBuilder {
@Override
public void buildBasic() {
System.out.println("高楼打地基");
}
@Override
public void buildWalls() {
System.out.println("高楼砌墙");
}
@Override
public void roofed() {
System.out.println("高楼封顶");
}
}
public class HouseDirector {
HouseBuilder houseBuilder = null;
public HouseDirector(HouseBuilder houseBuilder){
this.houseBuilder = houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
public House constructHouse(){
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
return houseBuilder.buildHouse();
}
}
public class Client {
public static void main(String[] args) {
//普通房子
CommonHouse commonHouse = new CommonHouse();
HouseDirector houseDirector = new HouseDirector(commonHouse);
House house = houseDirector.constructHouse();
System.out.println("------");
//高楼
houseDirector.setHouseBuilder(new HighHouse());
House highHouse = houseDirector.constructHouse();
}
}
建造者模式的注意细节
1.使用者不需知道产品内部的细节,将产品本身与产品的创建过程解耦,使用相同的创建过程可以创建不同的产品对象。
2.每一个具体建造者都相对独立。
3.可以更加精细的控制产品的创建过程。
4.增加新的具体建造者无须修改原有的代码。由指挥类针对抽象者类编程,易扩展,符合 开闭原则
5.建造者模式的产品有较多的共同点,若差异大,则不适合使用该模式。
6.若内部变化复杂,需要定义许多的具体建造者来实现变化,致使系统变得庞大,则需要考虑是否使用该模式。
建造者模式与抽象工厂的不同点
关注的侧重点不同。
抽象工厂主要是对产品家族的创建,具有不同维度的产品组合,不需要关系构建过程,只需关心什么工厂生产什么产品。
建造者模式需要按照指定的过程建造产品。主要目的是通过组装零件生产出一个新产品。