设计模式完结(5)-建造者模式
使用实例场景:
无论是何种造型的游戏角色,它的创建步骤都大同小异,都需要逐步创建其组成部分,再将各组成部分装配成一个完整的游戏角色。如何一步步创建一个包含多个组成部分的复杂对
象,建造者模式为解决此类问题而诞生。
建造者模式:
构建者-----具体部件建造者(钩子方法)
指挥者-----(可以通过钩子方法判断造那些部件)然后组装
是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。也就是将部件的创建和组装分离,互不影响。职责单一。
*****
builder 建造者主要负责各个部件的创建,同时也可以返回完整的产品product;
director 指挥者负责按顺序成产某些需要部件然后组装成完整的产品。
部件的创建都大同小异,组装的方法和顺序可能不同。
● Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。
●ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。
●Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。
● Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。
在建造者模式的结构中还引入了一个指挥者类Director,该类主要有两个作用:一方面它隔离了客户与创建过程;另一方面它控制产品的创建过程,包括某个buildPartX()方法是否被调用以及多个buildPartX()方法调用的先后次序等。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。
class Product { private String partA; //定义部件,部件可以是任意类型,包括值类型和引用类型 private String partB; private String partC; //partA的Getter方法和Setter方法省略 //partB的Getter方法和Setter方法省略 //partC的Getter方法和Setter方法省略 } abstract class Builder { //创建产品对象 protected Product product=new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); //返回产品对象 public Product getResult() { return product; } }
class Director { private Builder builder; public Director(Builder builder) { this.builder=builder; } public void setBuilder(Builder builder) { this.builder=builer; } //产品构建与组装方法 public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } } …… Builder builder = new ConcreteBuilder(); //可通过配置文件实现 Director director = new Director(builder); Product product = director.construct(); ……
//游戏角色创建控制器:指挥者
class ActorController
{
//逐步构建复杂产品对象
public Actor construct(ActorBuilder ab)
{
Actor actor;
ab.buildType();
ab.buildSex();
ab.buildFace();
ab.buildCostume();
ab.buildHairstyle();
actor=ab.createActor();
return actor;
}
}
*******
对象的组装过程可能不同,变化的地方就容易违反开闭原则,所以拆分出来指挥者。
2.
可以将Director和抽象建造者Builder进行合并:
abstract class ActorBuilder
{
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();
public Actor construct()
{
this.buildType();
this.buildSex();
this.buildFace();
this.buildCostume();
this.buildHairstyle();
return actor;
}
}
2.钩子方法的引入
建造者模式除了逐步构建一个复杂产品对象外,还可以通过Director类来更加精细地控制产品
的创建过程,例如增加一类称之为钩子方法(HookMethod)的特殊方法来控制是否对某个
buildPartX()的调用。
钩子方法的返回类型通常为boolean类型,方法名一般为isXXX(),钩子方法定义在抽象建造者
类中。例如我们可以在游戏角色的抽象建造者类ActorBuilder中定义一个方法isBareheaded(),
用于判断某个角色是否为“光头(Bareheaded)”,在ActorBuilder为之提供一个默认实现,其返回
值为false,代码如下所示:
abstract class ActorBuilder
{
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();
//钩子方法
public boolean isBareheaded()
{
return false;
}
public Actor createActor()
{
return actor;
}
}
如果某个角色无须构建头发部件,例如“恶魔(Devil)”,则对应的具体建造器DevilBuilder将覆
盖isBareheaded()方法,并将返回值改为true,代码如下所示:
class DevilBuilder extends ActorBuilder
{
public void buildType()
{
actor.setType("恶魔");
}
public void buildSex()
{
actor.setSex("妖");
}
public void buildFace()
{
actor.setFace("丑陋");
}
public void buildCostume()
{
actor.setCostume("黑衣");
}
public void buildHairstyle()
{
actor.setHairstyle("光头");
}
//覆盖钩子方法
public boolean isBareheaded()
{
return true;
}
}
此时,指挥者类ActorController的代码修改如下:
class ActorController
{
public Actor construct(ActorBuilder ab)
{
Actor actor;
ab.buildType();
ab.buildSex();
ab.buildFace();
ab.buildCostume();
//通过钩子方法来控制产品的构建
if(!ab.isBareheaded())
{
ab. buildHairstyle();
}
actor=ab.createActor();
return actor;
}
}
当在客户端代码中指定具体建造者类型并通过指挥者来实现产品的逐步构建时,将调用钩子方法isBareheaded()来判断游戏角色是否有头发,如果isBareheaded()方法返回true,即没有头发,则跳过构建发型的方法buildHairstyle();否则将执行buildHairstyle()方法。通过引入钩子方法,我们可以在Director中对复杂产品的构建进行精细的控制,不仅指定buildPartX()方法的执行顺序,还可以控制是否需要执行某个buildPartX()方法。
在以下情况下可以考虑使用建造者模式:
(1) 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
(2) 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
(3) 对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过
程封装在指挥者类中,而不在建造者类和客户类中。
(4) 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。