建造模式是对象的创建模式。建造模式可以将产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
一个例子
上古时期女娲造人,首先要新建一个人的类,但是女娲不只可以造人,它可以创造万物,所以,这里定义一个标识接口叫Product(产品)
public interface Product {
}
public class Man implements Product{
private String soul;//灵魂
private String earsAndEyes;//耳目
private String arm;//手臂
//。。。省略其他属性
public String getSoul() {
return soul;
}
public void setSoul(String soul) {
this.soul = soul;
}
public String getEarsAndEyes() {
return earsAndEyes;
}
public void setEarsAndEyes(String earsAndEyes) {
this.earsAndEyes = earsAndEyes;
}
public String getArm() {
return arm;
}
public void setArm(String arm) {
this.arm = arm;
}
}
那么想要造人需要有一定的标准和步骤,这里定义一个接口来规范创造的步骤(抽象的建造者):
public interface Builder {
//建造方法1
void buildPart1();
//建造方法2
void buildPart2();
//建造方法3
void buildPart3();
//返回产品的方法
Product productResult();
}
创造人的步骤是buildPart1》buildPart2》buildPart3,最后的方法是返回创造的这个人
具体的建造者
public class ManBuilder implements Builder {
private Man man = new Man();
@Override
public void buildPart1() {
man.setArm("男人--》生手臂");
}
@Override
public void buildPart2() {
man.setEarsAndEyes("男人--》生耳目");
}
@Override
public void buildPart3() {
man.setSoul("男人--》生灵魂");
}
@Override
public Man productResult() {
return man;
}
}
在创造人的过程中,冥冥之中有一个指挥者,指挥者委托女娲造人
public class Director {
public Man makeMan(Builder builder){
builder.buildPart1();
builder.buildPart2();
builder.buildPart3();
return (Man) builder.productResult();
}
}
测试代码
Director director = new Director();//客户端只需要跟指挥者打交道
Man man =director.makeMan(new ManBuilder());
System.out.println(man.getArm());
System.out.println(man.getEarsAndEyes());
System.out.println(man.getSoul());
上边例子中只有一个产品类,对应的也只有一个具体的建造者类。如果有两个产品的话,就应当有两个具体的建造者类,女娲造人之后感觉人类很孤单,决定造点动物玩玩:
public class Dog implements Product{
private String leg;
private String head;
public String getLeg() {
return leg;
}
public void setLeg(String leg) {
this.leg = leg;
}
public String getHead() {
return head;
}
public void setHead(String head) {
this.head = head;
}
}
dog的具体建造者:
public class DogBuilder implements Builder {
private Dog dog = new Dog();
@Override
public void buildPart1() {
dog.setLeg("狗--》生腿");
}
@Override
public void buildPart2() {
dog.setHead("狗--》生头");
}
@Override
public void buildPart3() {
}
@Override
public Dog productResult() {
return dog;
}
}
指挥者类相应的增加一个方法(makeDog):
public class Director {
public Man makeMan(Builder builder){
builder.buildPart1();
builder.buildPart2();
builder.buildPart3();
return (Man) builder.productResult();
}
public Dog makeDog(Builder builder){
builder.buildPart1();
builder.buildPart2();
builder.buildPart3();
return (Dog) builder.productResult();
}
}
测试:
Director director = new Director();
Man man =director.makeMan(new ManBuilder());
Dog dog =director.makeDog(new DogBuilder());
System.out.println(man.getArm());
System.out.println(man.getEarsAndEyes());
System.out.println(man.getSoul());
System.out.println("==============");
System.out.println(dog.getHead());
System.out.println(dog.getLeg());
本模式涉及到四个角色:
- 抽象建造者(Builder)角色:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口独立于应用程序的商业逻辑。产品对象有多少零件抽象建造者就应该有多少个建造方法。
- 具体建造者(ManBuilder)角色:这个角色是与应用程序紧密相关的一些类,此类要完成的任务包括:
- 实现抽象建造者接口,实现一步一步创建产品的步骤。
- 在建造完成后,提供产品的实例。
- 指挥者(Director)角色:调用具体建造者角色以创建产品对象。指挥者并没有产品类的具体知识,整整拥有产品类具体知识的是具体的建造者
- 产品(Man)角色:一般来说,一个系统中会有多于一个的产品类,而且这些类很有可能是不相关联的,所以需要建一个标识接口。
省略抽象建造者、省略指挥者
建造模式在实现时可以根据具体情况做一些变化。
首先,如果设计师确定只需要一个具体建造者角色的话,可以省略掉抽象建造者角色,因为如果只有一个具体建造者,就不需要什么规范了;抽象建造者被省略掉了,还可以在省略掉指挥者:
public class ManBuilder{
private Man man = new Man();
public void buildPart1() {
man.setArm("男人--》生手臂");
}
public void buildPart2() {
man.setEarsAndEyes("男人--》生耳目");
}
public void buildPart3() {
man.setSoul("男人--》生灵魂");
}
public Man productResult() {
return man;
}
//建造产品的方法
public Man makeProduct(){
buildPart1();
buildPart2();
buildPart3();
return productResult();
}
}
过渡到模板方法
准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。这就是模板方法模式。
有意思的是,这个特殊的建造模式与模板方法有相似之处,makeProduct就是一个模板方法,模板方法里边包含的就是基本方法。
如果系统的要求发生变化、要求有不同的零件生成逻辑时,那么有两种选择:一是修改这个退化的建造模式,将它改回成为完全的建造模式;二是不修改已有代码,将这个ManBuilder扩展到不同的子类,在这些子类里面置换掉需要改变的建造方法。
第一种选择了建造模式;第二种选择了模板方法模式。