1 建造者模式
建造者模式,是将一个复杂的对象的 构建 与它的 表示 分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
复制代码
首先看一个例子
1.盖房项目需求
(1) 需要建房子:这一过程为打桩、砌墙、封顶
(2) 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.
(3) 请编写程序,完成需求.
复制代码
2.传统方式解决
//面型接口编程,首先定义一个抽象类
public abstract class AbstractHouse {
public abstract void buildBasic();//打地基表示过程
public abstract void buildWalls();//砌墙表示过程
public abstract void roofed(); //封顶表示过程
//构建过程
public void build() {
buildBasic();
buildWalls();
roofed();
}
}
//盖一个普通的房子
public class CommonHouse extends AbstractHouse {
@Override
public void buildBasic() {
System.out.println(" 普通房子打地基 ");
}
@Override
public void buildWalls() {
System.out.println(" 普通房子砌墙 ");
}
@Override
public void roofed() {
System.out.println(" 普通房子封顶 ");
}
}
//盖一个高楼的房子
public class HighBuilding extends AbstractHouse {
@Override
public void buildBasic() {
System.out.println(" 高楼打地基 ");
}
@Override
public void buildWalls() {
System.out.println(" 高楼砌墙 ");
}
@Override
public void roofed() {
System.out.println(" 高楼封顶 ");
}
}
//测试类
public class Test {
public static void main(String[] args) {
AbstractHouse commonHouse = new CommonHouse();
commonHouse.build();
AbstractHouse highBuilding = new HighBuilding();
highBuilding.build();
}
}
复制代码
2.传统方式的问题分析
(1) 优点是比较好理解,简单易操作。
(2) 设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好. 也就是说,这种设计方案,把产 品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。
(3) 解决方案:将产品和产品建造过程解耦 => 建造者模式.
2 建造者模式基本介绍
建造者模式
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。
建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
角色
Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,电子邮件包括发件人、收件人、主题、内容、附件等部件
示例
1.产品角色 House
public class House {
private String baise;
private String wall;
private String roofed;
// 省略 getter, setter, toString
}
复制代码
2.抽象建造者 HouseBuilder
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;
}
}
复制代码
3.具体建造者 HighBuilding,CommonHouse
public class HighBuilding extends HouseBuilder {
@Override
public void buildBasic() {
System.out.println(" 高楼的打地基100米 ");
}
@Override
public void buildWalls() {
System.out.println(" 高楼的砌墙20cm ");
}
@Override
public void roofed() {
System.out.println(" 高楼的透明屋顶 ");
}
}
public class CommonHouse extends HouseBuilder {
@Override
public void buildBasic() {
System.out.println(" 普通房子打地基5米 ");
}
@Override
public void buildWalls() {
System.out.println(" 普通房子砌墙10cm ");
}
@Override
public void roofed() {
System.out.println(" 普通房子屋顶 ");
}
}
复制代码
4.指挥者 HouseDirector,指挥构建过程
//指挥者,这里去指定制作流程,返回产品
public class HouseDirector {
HouseBuilder houseBuilder = null;
//构造器传入 houseBuilder
public HouseDirector(HouseBuilder houseBuilder) {
this.houseBuilder = houseBuilder;
}
//通过setter 传入 houseBuilder
public void setHouseBuilder(HouseBuilder houseBuilder){
this.houseBuilder = houseBuilder;
}
//如何处理建造房子的流程,交给指挥者
public House constructHouse() {
houseBuilder.buildBasic();
houseBuilder.buildWalls();
houseBuilder.roofed();
return houseBuilder.buildHouse();
}
}
复制代码
5.客户端测试
public class Test {
public static void main(String[] args) {
//盖普通房子
CommonHouse commonHouse = new CommonHouse();
//准备创建房子的指挥者
HouseDirector houseDirector = new HouseDirector(commonHouse);
//完成盖房子,返回产品(普通房子)
House house = houseDirector.constructHouse();
//System.out.println("输出流程");
System.out.println("--------------------------");
//盖高楼
HighBuilding highBuilding = new HighBuilding();
//重置建造者
houseDirector.setHouseBuilder(highBuilding);
//完成盖房子,返回产品(高楼)
houseDirector.constructHouse();
}
}
复制代码
附:可以通过反射机制和配置文件配合,创建具体建造者对象
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
HouseDirector houseDirector = new HouseDirector();
// 从数据库或者配置文件中读取具体建造者类名
Class c = Class.forName("com.designpattern.CommonHouse");
CommonHouse commonHouse = (CommonHouse) c.newInstance();
House commonHouser = houseDirector.setHouseBuilder(commonHouse);
System.out.println(commonHouse.toString());
}
}
复制代码
3 建造者模式的注意事项和细节
优点:
1、使用建造者模式可以使客户端不必知道产品内部组成的细节。
2、具体的建造者类之间是相互独立的,这有利于系统的扩展。
3、具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
4、可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰, 也更方便使用程序来控制创建过程。
5、增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭 原则”。
复制代码
缺点:
1、 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使 用建造者模式,因此其使用范围受到一定的限制。
2、如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因 此在这种情况下,要考虑是否选择建造者模式。
复制代码
抽象工厂模式 VS 建造者模式
与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族 。
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,
而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车
复制代码
4 建造者模式在 JDK 的应用和源码分析
待补
复制代码