建造者模式(Builder)将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示。如果我们用了建造者模式,那么用户就只需要指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。
什么时候需要使用建造者模式?
主要用于创建一些复杂的对象,这些对象内部构造间的建造顺序通常是稳定的,但对象内部的构造通常面临着复杂的变化。它的好处是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。
先来看一下建造者模式的结构图
建造者是一个接口或者抽象类,由具体建造者来复杂构造和装配具体的产品的部件。而用户在使用时,是通过指挥者Director来间接调用接口。
下面来看一个实际的例子,假设现在要新建一个Human对象,它的属性如下,并且有展示方法,这个Human对象就是实际要建造的具体产品
public class Human {
private String height;
private String weight;
private String iq;
private String age;
public void show() {
System.out.println("开始打印");
System.out.println(height);
System.out.println(weight);
System.out.println(iq);
System.out.println(age);
System.out.println("打印结束");
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public String getWeight() {
return weight;
}
public void setWeight(String weight) {
this.weight = weight;
}
public String getIq() {
return iq;
}
public void setIq(String iq) {
this.iq = iq;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
然后是抽象建造者,它需要声明装配各个部件也就是属性的方法,和返回具体对象的抽象方法
public interface BuildHuman {
public void buildHead();
public void buildHeight();
public void buildWeight();
public void buildAge();
public Human createHuman();
}
实际建造者就是接口的实现类,根据需要不同,我们可以定义不同的具体实现类,比如下面的建造一个高智商对象和建造一个胖对象
public class SmartManBuilder implements BuildHuman {
private Human human;
public SmartManBuilder() {
human = new Human();
}
@Override
public void buildHead() {
human.setIq("智商180");
}
@Override
public void buildHeight() {
human.setHeight("身高170");
}
@Override
public void buildWeight() {
human.setWeight("体重130");
}
@Override
public void buildAge() {
human.setAge("年龄23");
}
@Override
public Human createHuman() {
return human;
}
}
public class FatManBuilder implements BuildHuman {
private Human human;
public FatManBuilder() {
human = new Human();
}
@Override
public void buildHead() {
human.setIq("智商100");
}
@Override
public void buildHeight() {
human.setHeight("身高180");
}
@Override
public void buildWeight() {
human.setWeight("体重180");
}
@Override
public void buildAge() {
human.setAge("年龄25");
}
@Override
public Human createHuman() {
return human;
}
}
指挥者需要做的是,根据用户给出的实际建造者,调用具体构造和拼装方法,最后返回实际产品
public class PersonDirector {
public static Human createHumanByDirecotr(BuildHuman bh) {
bh.buildAge();
bh.buildHead();
bh.buildHeight();
bh.buildWeight();
return bh.createHuman();
}
}
测试代码如下
public static void main(String[] args) {
BuildHuman bh = new SmartManBuilder();
Human smartHuman = PersonDirector.createHumanByDirecotr(bh);
smartHuman.show();
bh = new FatManBuilder();
Human fatHuman = PersonDirector.createHumanByDirecotr(bh);
fatHuman.show();
}
从测试代码中,我们可以看出,用户只需要给出具体的建造者就可以通过指挥者获取具体产品Human,而其中具体的调用和构造细节一概不知,而指挥者中只需要针对抽象的建造者接口进行编码调用,无需关心其中的具体实现,降低了耦合性。