1. 概述
在生活上,我们经常需要一个指南,按照一定的步骤去完成一件事情,很多符合条件的人都可以按照指南上的步骤去完成这件事情,但是不用关心这些个人是如何完成这些步骤的。这类情况就有点像是设计模式中的生成器模式(Builder)。
2. 生成器模式
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
生成器模式结构图如下
其中:
- Builder:生成器接口,定义创建一个Product对象所需的各个部件的操作。
- ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法。
- Director: 指导者,也被称为导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象。
- Product:产品,表示被生成器构建的复杂对象,包含多个部件。
下面用代码实现一下
(1)先看看生成器的接口定义,示例代码如下:
/**
* 生成器接口,定义创建一个产品对象所需的各个部件的操作
*/
public interface Builder {
/**
* 示意方法,构建某个部件
*/
public void buildPart();
}
(2)再看看具体的生成器实现,示例代码如下:
/**
* 具体的生成器实现对象
*/
public class ConcreteBuilder implements Builder {
/**
* 生成器最终构建的产品对象
*/
private Product resultProduct;
/**
* 获取生成器最终构建的产品对象
* @return 生成器最终构建的产品对象
*/
public Product getResult() {
return resultProduct;
}
public void buildPart() {
//构建某个部件的功能处理
}
}
(3)看看相应的产品对象的接口示意,示例代码如下:
/**
* 被构建的产品对象的接口
*/
public interface Product {
//定义产品的操作
}
(4)再来看看指导者的实现示意,示例代码如下:
/**
* 指导者,指导使用生成器的接口来构建产品的对象
*/
public class Director {
/**
* 持有当前需要使用的生成器对象
*/
private Builder builder;
/**
* 构造方法,传入生成器对象
* @param builder 生成器对象
*/
public Director(Builder builder) {
this.builder = builder;
}
/**
* 示意方法,指导生成器构建最终的产品对象
*/
public void construct() {
//通过使用生成器接口来构建最终的产品对象
builder.buildPart();
}
}
代码实现就到此结束了,下面用个具体实例的来加强理解。
3. 使用生成器模式
在前几年的手机里,诺基亚和三星占了很大的市场份额。大家应该还记得诺基亚的强大,手机一摔,直接分成3块,机身、电池和手机后盖,然后再把它们组装回去,又可以继续用了~~
现在,我就把手机当做(Product),诺基亚和三星手机便是手机的不同实现,而机身、电池和手机后盖就是手机的部件(Part),这些部件是制造商分别生产的。把这三个部件组装在一起,就可以使用该手机了。而组装步骤很简单:
- 将电池装上机身。
- 将手机后盖盖上。
现在就可以用代码来实现一下这个场景。
(1)先是手机的三个组成部件类,这些部件只有一个brand
字段代表品牌,其它细节便在此略过了~
1、机身(Body)
/**
* 机身
*/
public class Body {
// 所属品牌
private String brand;
// ..其它细节
public Body(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
}
2、电池(Battery)
/**
* 电池
*/
public class Battery {
// 所属品牌
private String brand;
// ..其它细节
public Battery(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
}
3、手机后盖(BackCover)
/**
* 手机后盖
*/
public class BackCover {
// 所属品牌
private String brand;
//..其它细节
public BackCover(String brand) {
this.brand = brand;
}
public String getBrand() {
return brand;
}
}
(2)手机类(Phone),有三个字段分别对应上面的三个部件类,并提供各自的getter和setter方法
/**
* 手机
*/
public class Phone {
private Body body;//机身
private Battery battery;//电池
private BackCover backCover;//后盖
public void setBody(Body body) {
this.body = body;
}
public void setBattery(Battery battery) {
this.battery = battery;
}
public void setBackCover(BackCover backCover) {
this.backCover = backCover;
}
public Body getBody() {
return body;
}
public Battery getBattery() {
return battery;
}
public BackCover getBackCover() {
return backCover;
}
}
(3)生成器接口,定义了创建一个手机(Phone)对象所需的各个部件的操作
/**
* 生产器接口,定义创建手机所需的各个部件的操作
*/
public interface Builder {
/**
* 构建机身
*/
public void buildBody();
/**
* 构建电池
*/
public void buildBattery();
/**
* 构建后盖
*/
public void buildBackCover();
}
(4)具体生成器的实现,一个是诺基亚(Nokia)的实现,一个是三星(Samsung)的实现
1、诺基亚(Nokia)的生成器实现
/**
* 诺基亚实现生成器对象
*/
public class NokiaBuilder implements Builder{
private Phone phone = new Phone();
/**
* 具体构建诺基亚机身
*/
public void buildBody() {
Body body = new Body("Nokia");
phone.setBody(body);
}
/**
* 具体构建诺基亚电池
*/
public void buildBattery() {
Battery battery = new Battery("Nokia");
phone.setBattery(battery);
}
/**
* 具体构建诺基亚后盖
*/
public void buildBackCover() {
BackCover backCover = new BackCover("Nokia");
phone.setBackCover(backCover);
}
public Phone getPhone() {
return phone;
}
}
2、三星(Samsung)的生成器实现
/**
* 三星实现生成器对象
*/
public class SamsungBuilder implements Builder{
private Phone phone = new Phone();
/**
* 具体构建三星机身
*/
public void buildBody() {
Body body = new Body("Samsung");
phone.setBody(body);
}
/**
* 具体构建三星电池
*/
public void buildBattery() {
Battery battery = new Battery("Samsung");
phone.setBattery(battery);
}
/**
* 具体构建三星后盖
*/
public void buildBackCover() {
BackCover backCover = new BackCover("Samsung");
phone.setBackCover(backCover);
}
public Phone getPhone() {
return phone;
}
}
(5)指导者(Director),指导生成器进行具体的产品构建
public class Director {
/**
* 生成器对象,通过构造方法传进来
*/
private Builder builder;
public Director(Builder builder) {
this.builder = builder;
}
/**
* 指导生成器构建产品
*/
public void construct(){
//1.构建机身
builder.buildBody();
//2.构建电池
builder.buildBattery();
//3.构建后盖
builder.buildBackCover();
}
}
(6)客户端(Client)来测试一下
public class Client {
public static void main(String[] args) {
// 创建具体的生成器
NokiaBuilder builder = new NokiaBuilder();
// SamsungBuilder builder = new SamsungBuilder();
// 创建指导者,并将生成器传入
Director director = new Director(builder);
// 指导者指导生成器构建产品
director.construct();
// 经过以上步骤,此时生成器中的手机对象便构建完毕
Phone phone = builder.getPhone();
// 将手机各个组件的品牌输出,看看是否一致
System.out.println("机身:" + phone.getBody().getBrand());
System.out.println("电池:" + phone.getBattery().getBrand());
System.out.println("后盖:" + phone.getBackCover().getBrand());
}
}
最终输出结果
机身:Nokia
电池:Nokia
后盖:Nokia
那么到此,生成器模式的使用就结束了,你可以发现,如果不使用生成器模式的话,那么在组装手机的时候,在每个具体的实现里都要重复这几个步骤,而生成器模式可以很好的将这些步骤“外包”给别人(指导者),分工鲜明。
4. 思考生成器模式
我觉得生成器模式最重要的两个角色就是生成器(Builder)和指导者(Director)
- 生成器:生成器定义了一个产品所需的各个部件的构建操作,但是如果它还要负责各个部件组装成一个产品的话,那就有点累了,这样子就不能完全关心自己分内的事情一样。就像是一个老师,除了专门教书外,还要管理学生的生活问题,这样子实在是浪费人才。
- 指导者:指导者知道如何将各个产品的部件组合成一个产品,不管他所接待的生产器给他生成的部件是如何实现的,生成器可以放心地将让指导者去捣鼓它生成的部件。就像是邓爷爷说的“不管白猫黑猫,抓到老鼠就是好猫”,给我一只猫(注意必须是猫哟),不管是黑的白的还是黄的花的,我都会训练它去给你抓老鼠~
不过要注意了,指导者的构建过程必须的统一的、固定不变的,变化的部分还是放在生成器中吧~
以上一部分内容参考至《研磨设计模式》