将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式第一种创建行模式,他讲客户端与包含多个部件的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。建造者模式关注如何一步一步的创建一个负责对象,不同的建造者定义了不同的建造过程。
Builder(抽象的建造者):他为创建一个产品对象的各个部件制定抽象接口,在该接口中一般声明两个方法,一个是创建对象属性的方法,另一个是用于返回复杂对象的方法。该类可以是抽象类,也可以是接口。
ConcreteBuilder(具体的建造者):他实现了Build接口,并重写父类方法。
Product(产品):他是被构建的复杂对象。定义各个部件(属性),具体的建造者负责建造他的部件。并定义它的装配过程。
Director(指挥者):指挥者又称为导演类,他负责安排创建复杂对象部件的次序,导演类与抽象建造者存在关联关系。可以在其construct()建造方法中调用建造者对象的部件构造与装配种方法,完成对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者的对象,然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者中。
建造者模式与抽象工厂模式都是较为复杂的创建型模式,建造者模式返回一个完整的负责的产品,抽象工厂模式返回一系列相关的产品;在抽象工厂模式中,客户端通过选择具体的工厂来生成岁需要的对象,而在建造者模式中,客户端通过执行具体建造者类型来指导导演类如何创建对象。
场景:游戏中的角色。
复杂对象类:角色,其中角色类型,性别,脸型,服装,发型等都为对象的部件
package com.gm.builder.one;
/**
* 角色对象, 充当产品,该产品由较为复杂的属性(组成部分)
*/
public class Actor {
/**
* 角色
*/
private String type;
/**
* 性别
*/
private String sex;
/**
* 脸型
*/
private String face;
/**
* 服装
*/
private String costume;
/**
* 发型
*/
private String hairstyle;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getFace() {
return face;
}
public void setFace(String face) {
this.face = face;
}
public String getCostume() {
return costume;
}
public void setCostume(String costume) {
this.costume = costume;
}
public String getHairstyle() {
return hairstyle;
}
public void setHairstyle(String hairstyle) {
this.hairstyle = hairstyle;
}
@Override
public String toString() {
return "Actor{" +
"type='" + type + '\'' +
", sex='" + sex + '\'' +
", face='" + face + '\'' +
", costume='" + costume + '\'' +
", hairstyle='" + hairstyle + '\'' +
'}';
}
}
抽象建造者:声明创建复杂对象的各个部件,并通过工厂方法返回复杂对象
package com.gm.builder.one;
/**
* 抽象建造者
*/
public abstract class ActorBuild {
protected Actor actor = new Actor();
/**
* 建造角色类型
*/
public abstract void buildType();
/**
* 建造性别
*/
public abstract void buildSex();
/**
* 建造脸型
*/
public abstract void buildFace();
/**
* 建造服装
*/
public abstract void buildCostume();
/**
* 建造发型
*/
public abstract void buildHairstyle();
/**
* 工厂方法,返回完成的对象
* @return
*/
public Actor createActor(){
return actor;
}
}
具体的创建者:天使创建者,英雄创建者,继承抽象建造者,并重写创建部件的方法,完成部件具体创建过程。
package com.gm.builder.one;
/**
* 天使角色
*/
public class AngleBuild extends ActorBuild {
@Override
public void buildType() {
actor.setType("天使");
}
@Override
public void buildSex() {
actor.setSex("女");
}
@Override
public void buildFace() {
actor.setFace("成熟脸");
}
@Override
public void buildCostume() {
actor.setCostume("性感的衣服");
}
@Override
public void buildHairstyle() {
actor.setHairstyle("大波浪");
}
}
package com.gm.builder.one;
/**
* 英雄角色
*/
public class HeroBuild extends ActorBuild {
@Override
public void buildType() {
actor.setType("英雄");
}
@Override
public void buildSex() {
actor.setSex("MAN");
}
@Override
public void buildFace() {
actor.setFace("美队的脸");
}
@Override
public void buildCostume() {
actor.setCostume("钢铁侠的衣服");
}
@Override
public void buildHairstyle() {
actor.setHairstyle("美队的发型");
}
}
导演类:其中的construct()方法进行安排创建部件的次序并逐步完成的创建。
package com.gm.builder.one;
/**
* 角色控制器,充当导演类
*/
public class ActorController {
/**
* 逐步创建产品的组件
* @param build
* @return
*/
public Actor construct(ActorBuild build){
build.buildType();
build.buildSex();
build.buildFace();
build.buildCostume();
build.buildHairstyle();
return build.createActor();
}
}
客户端
package com.gm.builder.one;
public class Client {
public static void main(String[] args) throws Exception{
ActorBuild build = (ActorBuild) Class.forName("com.gm.builder.one.AngleBuild").newInstance();
ActorController controller = new ActorController();
Actor actor = controller.construct(build);
System.out.println(actor);
}
}
运行结果
Actor{type='天使', sex='女', face='成熟脸', costume='性感的衣服', hairstyle='大波浪'}
导演类深入讨论
导演类是创建者模式的重要组成部分,控制创建对象部件的次序,并返回一个完整额对象,下面讨论几种导演类的变化形式:
1.省略导演类:
为了简化程序结构,可将导演类和抽象建造者进行合并,在抽象建造者中提供导演类的功能。可将construct()方法使用static修饰,以方便客户端调用。则抽象建造者的代码如下:
package com.gm.builder.two;
public abstract class ActorBuild {
protected static Actor actor = new Actor();
/**
* 建造角色类型
*/
public abstract void buildType();
/**
* 建造性别
*/
public abstract void buildSex();
/**
* 建造脸型
*/
public abstract void buildFace();
/**
* 建造服装
*/
public abstract void buildCostume();
/**
* 建造发型
*/
public abstract void buildHairstyle();
/**
* 工厂方法1,返回完成的对象,逐步创建产品的组件,用来替换导演类
* @return
*/
public Actor construct(){
this.buildType();
this.buildSex();
this.buildFace();
this.buildCostume();
this.buildHairstyle();
return actor;
}
/**
* 工厂方法2,返回完成的对象,逐步创建产品的组件,用来替换导演类
* @return
*/
public static Actor construct(ActorBuild build){
build.buildType();
build.buildSex();
build.buildFace();
build.buildCostume();
build.buildHairstyle();
return actor;
}
}
从而客户端的方法如下:
package com.gm.builder.two;
/**
* 客户端
*/
public class Client {
public static void main(String[] args) throws Exception{
//方法1
ActorBuild build = (ActorBuild) Class.forName("com.gm.builder.two.AngleBuild").newInstance();
Actor actor = build.construct();
System.out.println(actor);
//方法2
ActorBuild build2 = (ActorBuild) Class.forName("com.gm.builder.two.HeroBuild").newInstance();
Actor actor2 = ActorBuild.construct(build2);
System.out.println(actor2);
}
}
2.钩子方法引入
钩子方法通常为boolean型,方法名一般为is****(),钩子方法一边定义在抽象的建造者中。
抽象建造者;
package com.gm.builder.one;
/**
* 抽象建造者
*/
public abstract class ActorBuild {
protected Actor actor = new Actor();
/**
* 建造角色类型
*/
public abstract void buildType();
/**
* 建造性别
*/
public abstract void buildSex();
/**
* 建造脸型
*/
public abstract void buildFace();
/**
* 建造服装
*/
public abstract void buildCostume();
/**
* 建造发型
*/
public abstract void buildHairstyle();
/**
* 钩子方法
* @return
*/
public boolean isBareheaded(){
return false;
}
/**
* 工厂方法,返回完成的对象
* @return
*/
public Actor createActor(){
return actor;
}
}
具体建造者:
package com.gm.builder.one;
/**
* 英雄角色
*/
public class HeroBuild extends ActorBuild {
@Override
public void buildType() {
actor.setType("英雄");
}
@Override
public void buildSex() {
actor.setSex("MAN");
}
@Override
public void buildFace() {
actor.setFace("美队的脸");
}
@Override
public void buildCostume() {
actor.setCostume("钢铁侠的衣服");
}
@Override
public void buildHairstyle() {
actor.setHairstyle("美队的发型");
}
@Override
public boolean isBareheaded(){
return true;
}
}
通过引入钩子方法可以在导演类中对复杂对象进行精细化管理,不仅可以指定对象部件执行顺序,也可进行控制是否需要进行创建某个部件。
优势
1.客户端无需知道产品内部组成细节,将产品本身与产品创建过程进行解耦,使得相同的创建过程创建不同的对象。
2.每一个具体的建造者都是独立的,增加新的建造者无需修改原有类的代码,符合开闭原则
3.可以精细化控制对象的创建过程。
劣势
1.建造者模式一般所创建的产品对象都有较多的共同点,如果产品之间的差异性很大,不适用该模式。
2.产品内部变化复杂,可能会导致更多的具体建造者来进行创建,导致系统变得复杂。
1.需要生成的产品对象有复杂的内部结构,这些产品通常包含对个成员变量。
2.需要生成的产品属性相互依赖,需要指定其生成顺序。
3.对象的创建过程独立于创建该对象的类型。
4.复杂对象的创建和使用,并使得相同创建过程可以创建不同对象。