概念
将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以有不同的表示。
大概的意思是说:一套的构建过程可以有不同的产品(表示)出来。这些产品(表示)都按照这一套的构建过程被生产出来。
初探
建造者模式属于创建型模式。比如说:楼房是千差万别的,楼房的外形,层数,内部房间的数量,房间的装饰都不一样。但是对于建造者来说,抽象出来的建筑流程是确定的。因为建筑一座楼房,都可以归纳为几个步骤:1打桩、2建地基、3搭框架、4内部建设。同理,建造者设计模式也是基于这样的概念而生的,这个设计模式用来解决什么样的情况呢:即流程不变,但每个流程实现的具体细节是会变化的。这样的情况,可以考虑使用建造者。就像盖房子,4个流程都必须有,但每个流程各自的实现细节,各个房子各有不同。 建造者模式的好处就是保证了流程不会变化,即流程不会增加也不会遗漏,也不会产生流程次序的错误。而建造者模式,保证了流程的确定性,而流程内部的实现细节,是可继承扩展的。从根源上解决了流程不规范的问题。
写代码的时候,如果你遇到一个需要把控流程,但流程中的实现细节各有许多的方式,你可以采用建造者模式。用一个director类把控流程,而用许多不同的builder去建造流程中的细节并产生产品。这样,生产出来的产品基本是不会出问题的。因为流程把控好了。你可以有多个builder去负责建造生产产品,而让director去把控流程。如果有新的产品,但是流程一致,你可以再扩张出一个builder来。这样,你看,建造者模式是不是很符合OCP原则呢。
建造者模式注重于房子的零部件的组装的顺序,而工厂模式则注重于创建怎样的房子.
建造者模式要求建造的过程必须是稳定的,而装饰模式没有这个要求
模式中的角色分类
- Builder:给出一个抽象接口,规范建造者对于生产的产品的各个组成部分的建造。这个接口只是定一个规范,不涉及具体的建造,具体的建造让继承于它的子类(ConcreteBuilder)去实现
- ConcreteBuilder:实现builder接口,针对不同的商业逻辑,具体化各对象部分的建造,最后返回一个建造好的产品。实现抽象类的所有未实现的方法,具体来说一般是两项任务:组建产品;返回组建好的产品。
- Director:导演(负责人),顾名思义,负责规范流程之用。在指导中不涉及产品的创建,只负责保证复杂对象各部分被创建或按某种顺序创建。导演类一般不与产品类发生依赖关系,与导演类直接交互的是建造者类。一般来说,导演类被用来封装程序中易变的部分。
- Product:复杂对象。
角色UML关系图如下
以创建AlertDialog为例子
目前,创建者模式,有很多变种.
标准模式
UML图如下
java代码
抽象接口
package demo10;
/**
*
* @ClassName: DialogBuilder
* @Description:抽象接口
* @author cheng
* @date 2017-8-15 下午02:02:06
*/
public interface DialogBuilder {
/**
*
* @Title: createBackGround
* @Description: 创建背景
* @param s
* @return
*/
DialogBuilder createBackGround(String s);
/**
*
* @Title: createShape
* @Description: 创建形状
* @param s
* @return
*/
DialogBuilder createShape(String s);
/**
*
* @Title: createTitle
* @Description: 创建标题
* @param s
* @return
*/
DialogBuilder createTitle(String s);
/**
*
* @Title: build
* @Description: 创建对象并返回
* @return
*/
Object build();
}
具体实现类
package demo10;
/**
*
* @ClassName: AlertDialogBuilder
* @Description:具体构建类
* @author cheng
* @date 2017-8-15 下午02:13:39
*/
public class AlertDialogBuilder implements DialogBuilder {
//持有产品的引用
private AlertDialog alertDialog;
public AlertDialogBuilder() {
alertDialog = new AlertDialog();
}
@Override
public DialogBuilder createBackGround(String s) {
alertDialog.setBackGround(s);
return this;
}
@Override
public DialogBuilder createShape(String s) {
alertDialog.setShape(s);
return this;
}
@Override
public DialogBuilder createTitle(String s) {
alertDialog.setTitle(s);
return this;
}
@Override
public AlertDialog build() {
return alertDialog;
}
}
产品类
package demo10;
/**
*
* @ClassName: AlertDialog
* @Description:产品类
* @author cheng
* @date 2017-8-15 下午02:08:35
*/
public class AlertDialog {
private String backGround;
private String shape;
private String title;
/**
* 复写
*/
@Override
public String toString() {
return "AlertDialog[backGround=" + backGround + ",shape=" + shape
+ ",title=" + title + "]";
}
public AlertDialog() {
}
public AlertDialog(String backGround, String shape, String title) {
super();
this.backGround = backGround;
this.shape = shape;
this.title = title;
}
public String getBackGround() {
return backGround;
}
public void setBackGround(String backGround) {
this.backGround = backGround;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
导演类
package demo10;
/**
*
* @ClassName: DialogDirector
* @Description:导演类
* @author cheng
* @date 2017-8-15 下午02:19:11
*/
public class DialogDirector {
// 持有抽象接口的引用
private DialogBuilder dialogBuilder;
public DialogDirector() {
dialogBuilder = new AlertDialogBuilder();
}
public AlertDialog createDialog(String background, String shape,
String title) {
return (AlertDialog) dialogBuilder.createBackGround(background)
.createShape(shape).createTitle(title).build();
}
}
测试
package demo10;
/**
*
* @ClassName: ClientTest
* @Description:测试
* @author cheng
* @date 2017-8-15 下午02:21:52
*/
public class ClientTest {
public static void main(String[] args) {
AlertDialog alertDialog1 = new DialogDirector().createDialog("黑色",
"长方形", "是否删除");
System.out.println(alertDialog1);
}
}
运行结果
链式简版
只包括建造者类,产品参数内部类,产品类
UML图如下
java代码
具体建造类
package demo11;
/**
*
* @ClassName: AlertDialogBuilder
* @Description:具体构建类
* @author cheng
* @date 2017-8-15 下午02:13:39
*/
public class AlertDialogBuilder {
private AlertDialogParams alertDialogParams;
/**
* 初始化建造者,初始化AlertDialogparams中间件
*/
public AlertDialogBuilder() {
alertDialogParams = new AlertDialogParams();
}
/**
*
* @ClassName: AlertDialogparams
* @Description:内部类来作为中间量,作为建造对象的参数传入,属性和产品类相同
* @author cheng
* @date 2017-8-15 下午03:58:21
*/
class AlertDialogParams {
String backGround;
String shape;
String title;
}
/**
*
* @Title: createBackGround
* @Description: 返回自身AlertDialogBuilder,链式调用
* @param s
* @return
*/
public AlertDialogBuilder createBackGround(String s) {
alertDialogParams.backGround = s;
return this;
}
public AlertDialogBuilder createShape(String s) {
alertDialogParams.shape = s;
return this;
}
public AlertDialogBuilder createTitle(String s) {
alertDialogParams.title = s;
return this;
}
/**
* 新建AlertDialog对象,将中间量alertDialogParams传入AlertDialog,进行构建.
*/
public AlertDialog build() {
AlertDialog alertDialog = new AlertDialog();
alertDialog.init(alertDialogParams);
return alertDialog;
}
}
产品类
package demo11;
/**
*
* @ClassName: AlertDialog
* @Description:产品类
* @author cheng
* @date 2017-8-15 下午03:50:09
*/
public class AlertDialog {
private String backGround;
private String shape;
private String title;
/**
*
* @Title: init
* @Description: 初始化
* @param params
*/
public void init(AlertDialogBuilder.AlertDialogParams params) {
this.backGround = params.backGround;
this.shape = params.shape;
this.title = params.title;
}
/**
* 复写
*/
@Override
public String toString() {
return "AlertDialog[backGround=" + backGround + ",shape=" + shape
+ ",title=" + title + "]";
}
public AlertDialog() {
}
public String getBackGround() {
return backGround;
}
public void setBackGround(String backGround) {
this.backGround = backGround;
}
public String getShape() {
return shape;
}
public void setShape(String shape) {
this.shape = shape;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
测试
package demo11;
/**
*
* @ClassName: ClientTest
* @Description:测试
* @author cheng
* @date 2017-8-15 下午02:21:52
*/
public class ClientTest {
public static void main(String[] args) {
AlertDialog alertDialog = new AlertDialogBuilder()
.createBackGround("黑色")
.createShape("圆形")
.createTitle("确认登录")
.build();
System.out.println(alertDialog);
}
}
运行结果
好处
使用建造者模式可以使客户端不必知道产品内部组成的细节。
具体的建造者类之间是相互独立的,对系统的扩展非常有利。
由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他的模块产生任何影响。
使用场合
创建一些复杂的对象时,这些对象的内部组成构件间的建造顺序是稳定的,但是对象的内部组成构件面临着复杂的变化
要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。