一、创建型模式
文章目录
建造者模式
1.概述
1.1 问题:
假设你要建造一座房子,最简单的是,先你需要建造四面墙和地板, 安装房门和一套窗户, 然后再建造一个屋顶。
但是如果你想要一栋更宽敞更明亮的房屋,还想要暖气、排水和泳池等之类的又该怎么办?
public class Product {
/**
* 地基,必须建造
*/
private String base;
/**
* 墙壁,必须建造
*/
private String wall;
/**
* 屋顶,必须建造
*/
private String roof;
/**
* 游泳池,可选建造
*/
private String swimmingPool;
/**
* 暖气,可选建造
*/
private String heating;
/**
* 花园,可选建造
*/
private String garden;
}
1.2 解决方案
这里现在有两个解决方法,一种是创建很多不同参数的构造方法(折叠构造函数模式),来满足不同的需求,但是这样灵活性较差;第二种是使用JavaBean,setter方法实例化对象。这里的属性设置是分开的,如果参数过多,很可能会出现遗漏和出错的情况。
1.2.1 使用不同参数的构造方法实现
代码展示
public Product(String base, String wall, String roof) {
this(base, wall, roof, "大游泳池");
}
public Product(String base, String wall, String roof, String swimmingPool) {
this(base, wall, roof, swimmingPool, "地暖");
}
public Product(String base, String wall, String roof, String swimmingPool, String heating) {
this(base, wall, roof, swimmingPool, heating, "花园");
}
public Product(String base, String wall, String roof, String swimmingPool, String heating, String garden) {
this.base = base;
this.wall = wall;
this.roof = roof;
this.swimmingPool = swimmingPool;
this.heating = heating;
this.garden = garden;
}
1.2.2 使用JavaBean,setter实例化对象
public String getBase() {
return base;
}
public void setBase(String base) {
this.base = base;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
public String getSwimmingPool() {
return swimmingPool;
}
public void setSwimmingPool(String swimmingPool) {
this.swimmingPool = swimmingPool;
}
//后面省略
2.实现
2.1 分析
场景分析
建造者模式建议将对象构造代码从产品类中抽取出来, 并将其放在一个名为生成器的独立对象中。
将建造房子分成创建墙壁,创建房门,创建窗户等…,然后将创建房子分为固定的步骤, 组建房子的步骤是一样的。如果你想要不同的参数,只需要替换其中的某一个步骤就可以。
结构分析
Product
: 最终要生成的对象,例如 House实例。
Builder
: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,(构建房子的步骤)其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。
ConcreteBuilder
(具体建造者): Builder的实现类。
Director(指导者)
: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct()方法获得最终的产品。
类图分析
2.1 Product类
public class Product {
/**
* 地基,必须建造
*/
private String base;
/**
* 墙壁,必须建造
*/
private String wall;
/**
* 屋顶,必须建造
*/
private String roof;
/**
* 游泳池,可选建造
*/
private String swimmingPool;
/**
* 暖气,可选建造
*/
private String heating;
/**
* 花园,可选建造
*/
private String garden;
public Product(String base, String wall, String roof) {
this.base = base;
this.wall = wall;
this.roof = roof;
}
//省略setter和getter方法
}
2.2Builder接口
package com.renlon.Builder;
/**
* 抽象构建者,定义了构建房子的抽象步骤
*
* @author: renlon 2023/03/02 23:53
*/
public interface Builder {
/**
* 建造游泳池
*/
void buildSwimmingPool();
/**
* 建造地暖
*/
void buildHeating();
/**
* 建造花园
*/
void buildGarden();
/**
* 得到产品
*
* @return 返回产品
*/
Product get();
}
2.3ConcreteBuilder实现类
- 实现类A
package com.renlon.Builder;
/**
* 实体房子A
*
* @author: renlon 2023/03/02 23:54
*/
public class ConcreteBuilderA implements Builder {
private Product product;
/**
* 一个房子必须要构建地基,墙壁和屋顶
*
* @param base 用户指定的地基样式
* @param wall 用户指定的墙壁样式
* @param roof 用户指定的屋顶样式
*/
public ConcreteBuilderA(String base, String wall, String roof) {
product = new Product(base, wall, roof);
}
/**
* 以下为可选实现功能,如果无需此设施,可选择不写方法体
*/
@Override
public void buildSwimmingPool() {
product.setSwimmingPool("游泳池A");
}
@Override
public void buildHeating() {
//A房子没有地暖
}
@Override
public void buildGarden() {
product.setGarden("皇家后花园");
}
/**
* 获得此产品
*
* @return 返回改产品
*/
@Override
public Product get() {
return product;
}
}
- 实现类B
package com.renlon.Builder;
/**
* 实体房子B
*
* @author: renlon 2023/03/02 23:56
*/
public class ConcreteBuilderB implements Builder {
private Product product;
/**
* 一个房子必须要构建地基,墙壁和屋顶
*
* @param base 用户指定的地基样式
* @param wall 用户指定的墙壁样式
* @param roof 用户指定的屋顶样式
*/
public ConcreteBuilderB(String base, String wall, String roof) {
product = new Product(base, wall, roof);
}
/**
* 以下为可选实现功能,如果无需此设施,可选择不写方法体
*/
@Override
public void buildSwimmingPool() {
product.setSwimmingPool("游泳池B");
}
@Override
public void buildHeating() {
product.setHeating("地暖B");
}
@Override
public void buildGarden() {
//B房子没有花园
}
/**
* 获得此产品
*
* @return 返回改产品
*/
@Override
public Product get() {
return product;
}
}
2.4 Director指挥类
package com.renlon.Builder;
/**
* @author: renlon 2023/03/02 23:54
*/
public class Director {
/**
* 按照顺序执行构建房子的步骤
*
* @param builder 构建者,定义了构建房子的抽象步骤
*/
public void construct(Builder builder) {
builder.buildSwimmingPool();
builder.buildHeating();
builder.buildGarden();
}
}
2.5检测
package com.renlon.Builder;
/**
* @author: renlon 2023/03/03 19:49
*/
public class Demo {
public static void main(String[] args) {
//创建指导者对象
Director director = new Director();
//创建A房子,传入必须构造的地基,墙壁,屋顶参数
ConcreteBuilderA builderA = new ConcreteBuilderA("地基A", "木头墙壁", "玻璃屋顶");
//指导者调用方法,构建A的可选构造设施
director.construct(builderA);
//获得最终的A房子
Product productA = builderA.get();
System.out.println(productA.toString());
ConcreteBuilderB builderB = new ConcreteBuilderB("地基B", "石头墙壁", "金属屋顶");
director.construct(builderB);
Product productB = builderB.get();
System.out.println(productB.toString());
}
}
运行结果
Product{base='地基A', wall='木头墙壁', roof='玻璃屋顶', swimmingPool='游泳池A', heating='null', garden='皇家后花园'}
Product{base='地基B', wall='石头墙壁', roof='金属屋顶', swimmingPool='游泳池B', heating='地暖B', garden='null'}
3. 总结
3.0 概念
建造者模式是一种创建型设计模式,也叫生成器模式,用户只需要指定需要建造的类型就可以得到该类型对应的产品实例 , 不关心建造过程细节 。实际上就是构建包含多个组件的对象 , 采用相同的构建过程 , 创建不同的产品 。
3.1 优点
- 降低耦合性:建造者模式可以将对象的创建与使用分离,降低了对象之间的耦合性,使得系统更加灵活、易于维护和扩展。
- 增加可读性:使用建造者模式可以将复杂对象的创建过程分解为多个简单的步骤,使得代码更加清晰、易于理解和维护。
- 提高灵活性:通过建造者模式可以使用相同的创建过程来创建不同类型的对象,从而提高了系统的灵活性。
- 可以控制对象的创建过程:建造者模式可以控制对象的创建过程,从而可以根据需要对创建过程进行优化和调整,提高对象的性能和质量。
3.2 缺点
建造者模式的实现较为复杂,需要定义多个类和接口,因此增加了系统的复杂性。
如果对象较为简单,使用建造者模式可能会导致代码冗余,降低代码的可读性和可维护性。
对象创建过程一旦开始就无法中途取消或修改,因此建造者模式不适用于需要动态调整对象创建过程的场景。
3.3 工厂模式和建造者模式对比
建造者模式和工厂模式的不同点在于它们解决的问题和实现的方式。
建造者模式更适用于创建复杂的对象,而工厂模式更适用于创建简单的对象。建造者模式通常需要一个指导者来控制构建过程, 通过设置不同的可选参数,“定制化”创建不同属性的对象。
工厂模式只需要一个工厂类即可。此外,建造者模式通常会在最终创建对象之前进行多个步骤的处理,而工厂模式直接创建对象。
3.4 适用场景
结构复杂
:对象有非常复杂的内部结构,有很多的属性
分离创建和使用
:想把复杂对象的创建和使用分离当创建一个对象需要很多的步骤,适合使用建造者模式。当创建一个对象,只需要一个简单的方法就可以完成,适合使用工厂模式。