建造者模式(Builder Pattern)属于创建型模式;何为创建型模式?就是帮我们省去直接new的过程,从而帮助我们更好的创建对象。建造者模式又叫生成器模式,它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。建造者模式 是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
就好比我们要买一辆汽车,我们可以直接告诉卖车的人我们需要的型号即可,然后付费就可以得到一辆汽车了,而汽车的制造过程是非常复杂的,用户却无需知道。从代码的角度来说,我们要得到一个复杂的汽车对象,我们只需要说出对象的类型和内容即可,通过建造者模式就可以给我们返回一个复杂的对象,而对象内部的创建过程和细节我们无需知道。
要引出建造者模式,最典型的例子就是盖房问题,我们知道,要想得到一个房子,需要经过打地基、砌墙、封顶、粉刷一系列的过程;造出来房子有各种各样的,比如普通房,高楼,别墅,虽然各种房子的制造过程是一样的,但是具体的要求还是有区别的,例如我们造一个普通的房子需要打地基5米,而造一栋高楼却需要打地基50米。现在要求我们编码实现造房子的需求。
传统的解决方案: 由于不同的房子制造过程是一样的,只是具体实现不同,那我们可以抽象出一个顶级房子类,可以是抽象类也可以是接口,包含制造房子的一系列抽象方法,然后具体的房子去继承抽象房子,实现抽象方法。客户要想得到一个房子对象,直接去new创建即可。这样做的弊端就是把产品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。
而建造者模式就是将产品和产品建造过程分开,实现解耦。从建造者模式来实现盖房子问题:如果我们要盖一座房子,首先去找一个承包商(指挥者),也可以简单的理解成包工头,指挥者通过造房图纸(抽象的建造者)来指挥工人(具体的建造者)去建房子,最后完工。
类图:
代码示例:
产品角色
//具体的产品:房子类
public class House {
private String A;//地基
private String B;//墙
private String C;//屋顶
private String D;//粉刷
// 省略get、set及toString方法
}
抽象建造者角色
//抽象的建造者:提供造房的一系列流程
public abstract class HouseBuilder {
abstract void buildA();//打地基
abstract void buildB();//砌墙
abstract void buildC();//封顶
abstract void buildD();//粉刷
abstract House build();//完成造房,返回房子对象
}
具体建造者角色
//具体的建造者:普通房子
public class CommonHouse extends HouseBuilder{
private House house;
public CommonHouse() {
house=new House();
}
@Override
void buildA() {
house.setA("普通房子的地基");
System.out.println("普通房子打地基5米");
}
@Override
void buildB() {
house.setB("普通房子的墙");
System.out.println("普通房子砌墙2米");
}
@Override
void buildC() {
house.setA("普通房子的屋顶");
System.out.println("普通房子进行封顶");
}
@Override
void buildD() {
house.setD("普通房子的粉刷");
System.out.println("普通房子进行粉刷");
}
@Override
House build() {
return house;
}
}
具体建造者角色
//具体的建造者:高楼
public class HighBuilding extends HouseBuilder{
private House house;
public HighBuilding() {
house=new House();
}
@Override
void buildA() {
house.setA("高楼的地基");
System.out.println("高楼打地基50米");
}
@Override
void buildB() {
house.setB("高楼的墙");
System.out.println("普通房子砌墙20米");
}
@Override
void buildC() {
house.setA("高楼的屋顶");
System.out.println("高楼进行封顶");
}
@Override
void buildD() {
house.setD("高楼的粉刷");
System.out.println("高楼进行粉刷");
}
@Override
House build() {
return house;
}
}
指挥者角色
//指挥者:可以控制房子的生产流程
public class Director {
private HouseBuilder houseBuilder;
public Director(HouseBuilder houseBuilder){
this.houseBuilder=houseBuilder;
}
public void setHouseBuilder(HouseBuilder houseBuilder){
this.houseBuilder=houseBuilder;
}
public House construct(){
houseBuilder.buildA();
houseBuilder.buildB();
houseBuilder.buildC();
houseBuilder.buildD();
return houseBuilder.build();
}
}
客户端/测试类
public class Client {
public static void main(String[] args) {
//创建一个指挥者对象,并传入生产普通房子的具体建造者
Director director=new Director(new CommonHouse());
//通过建造者生产房子
House house = director.construct();
}
}
建造者模式的四个角色
- Product(产品角色): 一个具体的产品对象
- Builder(抽象建造者): 创建一个 Product 对象的各个部件指定的接口/ 抽象类;或者说是声明了创建产品需要的抽象方法
- ConcreteBuilder(具体建造者): 实现接口或继承抽象类,构建和装配各个部件;或者说是实现了生产产品的方法
- Director(指挥者): 构建一个使用 Builder 接口的对象。它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整的产品类。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。
建造者模式的优点
- 产品的建造和表示分离,实现了解耦,使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰。
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合"开闭原则"。
建造者模式的缺点
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要很多具体建造者类来实现这种变化,导致系统变得很庞大。
建造者模式和工厂模式的区别
关于工厂模式,可以参考:https://blog.csdn.net/can_chen/article/details/105924115
- 工厂模式一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个产品的组成部分。从代码上看,工厂模式就是一个方法,用这个方法就能生产出产品。
- 建造者模式也是创建一个产品,但是不仅要把这个产品创建出来,还要关系这个产品的组成细节,组成过程。从代码上看,建造者模式在建造产品时,这个产品有很多方法,建造者模式会根据这些相同方法但是不同执行顺序建造出不同组成细节的产品。
- 工厂模式关心整体,创建的是一批对象;而建造者模式关心细节,围绕一个对象的创建流程。
应用场景
java.lang.StringBuilder类就就用到了建造者模式