首先我们还是提出一个需求,分别使用传统方式以及建造者模式进行实现。让大家更好的根据代码区分出设计模式不同所带来的差别。
需求
盖房子:
- 建造房子:这一过程为打桩、砌墙、封顶
- 房子有各种各样的,比如普通房子,高层,别墅等等。虽然建造过程都一样,但是房子的参数值不一样,比如房子的地基深度以及房子的高度。
- 请编写程序,完成需求。
传统方式解决盖房子需求
首先提供房子抽象类
public abstract class AbstractHouse {
//挖地基
public abstract void buildBasic();
//墙面
public abstract void buildWall();
//封顶
public abstract void roofed();
//建造
public void build(){
buildBasic();
buildWall();
roofed();
}
}
具体的实现类(普通房子)
public class CommonHouse extends AbstractHouse{
@Override
public void buildBasic() {
System.out.println("普通房子挖地基5米");
}
@Override
public void buildWall() {
System.out.println("普通房子贴墙面10厘米");
}
@Override
public void roofed() {
System.out.println("普通房子封顶");
}
}
具体实现类(高楼)
public class HighHouse extends AbstractHouse{
@Override
public void buildBasic() {
System.out.println("高楼挖地基10米");
}
@Override
public void buildWall() {
System.out.println("高楼贴墙面20厘米");
}
@Override
public void roofed() {
System.out.println("高楼封顶");
}
}
客户端
public class Client {
public static void main(String[] args) {
CommonHouse commonHouse = new CommonHouse();
commonHouse.build();
}
}
我们看下输出
普通房子挖地基5米
普通房子贴墙面10厘米
普通房子封顶
当前传统方法的总结
- 优点是好理解,使用简单。
- 缺点是程序设计的过于简单,缺少缓存层对象。程序不利于拓展和维护。这种设计方案把产品(房子)和构建过程都放到了一起。增加了耦合度。
解决办法:将产品和产品建造过程解耦,===> 使用建造者模式。
建造者模式基本介绍
- 建造者模式 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
- 建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们。用户不需要知道内部的具体构建细节。
建造者模式的四个角色
- Product(产品):一个具体的产品对象。
- Builder(抽象建造者): 定义一个Product的抽象构建方法。(接口/抽象类)
- ConcreteBuilder(具体建造者): 根据具体的产品实现每个抽象构建方法。
- Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象,它的主要功能有两个:一是隔离了客户与对象的生产过程,二是负责控制产品对象的生产过程。
使用建造者模式解决需求
产品:(房子类)
@Data
public class House {
//地基
private String basic;
//墙
private String wall;
//封顶
private String roofed;
}
抽象建造者
public abstract class Builder {
protected House house = new House();
//定义好抽象流程
//挖地基
public abstract void buildBasic();
//墙面
public abstract void buildWall();
//封顶
public abstract void roofed();
//返回产品
public House getHouse(){
return house;
}
}
具体的实现者:(普通房子)
public class CommonHouse extends Builder{
@Override
public void buildBasic() {
house.setBasic("5米");
System.out.println("普通房子挖地基5米");
}
@Override
public void buildWall() {
house.setWall("10厘米");
System.out.println("普通房子贴墙面10厘米");
}
@Override
public void roofed() {
house.setRoofed("普通房子封顶");
System.out.println("普通房子封顶");
}
}
具体的实现者:(高楼)
public class HighBuilding extends Builder{
@Override
public void buildBasic() {
house.setBasic("10米");
System.out.println("高楼挖地基10米");
}
@Override
public void buildWall() {
house.setWall("20厘米");
System.out.println("高楼贴墙面20厘米");
}
@Override
public void roofed() {
house.setRoofed("高楼封顶");
System.out.println("高楼封顶");
}
}
指挥者
public class HouseDirect {
private Builder builder = null;
public HouseDirect(Builder builder) {
this.builder = builder;
}
public House initHouse(){
builder.buildBasic();
builder.buildWall();
builder.roofed();
return builder.getHouse();
}
}
客户端
public class Client {
public static void main(String[] args) {
HouseDirect houseDirect = new HouseDirect(new CommonHouse());
House house = houseDirect.initHouse();
System.out.println(house);
HouseDirect houseDirect1 = new HouseDirect(new HighBuilding());
House house1 = houseDirect1.initHouse();
System.out.println(house1);
}
}
输出:
普通房子挖地基5米
普通房子贴墙面10厘米
普通房子封顶
House(basic=5米, wall=10厘米, roofed=普通房子封顶)
高楼挖地基10米
高楼贴墙面20厘米
高楼封顶
House(basic=10米, wall=20厘米, roofed=高楼封顶)
建造者模式的注意事项和细节
- 客户端不需要知道产品内部的组成细节,将产品本身与建造过程进行解耦,使相同的构建过程可以构建出不同的产品对象。
- 每一个具体建造者都相对独立,与其他具体建造者都不相关,因此可以很方便的替换具体建造者或创建新的具体建造者,用户使用不同的具体建造者就可以获得不同的产品对象。
- 可以更加精细的控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造类,无需修改其他原有代码。指挥者对抽象建造者变成,方便拓展,符合“开闭原则”。
- 建造者模式所创建的产品对象都有很多共同点,其组成部分很相似,如果产品之间的差异性很大,则不适合使用建造者模式。 因此其使用范围受到一定限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多的具体建造类来实现这种变化,导致系统变得很庞大,因此在这种情况,要考虑是否选择建造者模式。
- 抽象工厂模式 vs 建造者模式
抽象工厂模式实现对产品家族的创建,一个产品家族是一个系列的产品,具有不同的分类纬度的产品组合,采用抽象工厂模式不需要关心构建过程只需要关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零件的方式生产一个产品。