建造者模式(Build Pattern)又称生成器模式,该模式封装一个产品的构造过程,一步一步地创建出一个复杂的对象,它允许用户通过指定复杂对象的类型和具体内容来构建对象,不需要知道内部的构建细节。
下面应用建造者模式来解决一个实际案例
假设你在广州做一个导游,现在你需要为游客制定多个“羊城一日游”的行程安排的计划,其中每个计划去的景点可能不太一样,另外如果是外地的游客则需要提供旅馆住宿。
所以需要一个弹性的数据结构,代表客人的规划以及所有的变化。要创建这样的计划,就需要使用建造者模式来实现创建复杂的结构的同时,又不会和创建它的步骤混在一起。
Plan类,担当产品对象的角色
public class Plan {
public String morningPlan;
public String afternoonPlan;
public String nightPlan;
public String sleepPlan;
//省略getter和setter方法
//省略toString方法
Director类,担当指挥者的角色
public class Director {
AbstractBuilder planBuilder;
public Director(AbstractBuilder planBuilder) {
// TODO Auto-generated constructor stub
this.planBuilder = planBuilder;
}
public void setPlanBuilder(AbstractBuilder planBuilder) {
this.planBuilder = planBuilder;
}
public Plan constructPlan() {
System.out.println("计划制定:");
planBuilder.arrangeMorning();
planBuilder.arrangeAfternoon();
planBuilder.arrangeNight();
planBuilder.arrangeSleep();
return planBuilder.getPlan();
}
}
AbstractPlanBuilder类,担当抽象建造者的角色
public abstract class AbstractBuilder {
Plan plan = new Plan();
public abstract void arrangeMorning();
public abstract void arrangeAfternoon();
public abstract void arrangeNight();
public abstract void arrangeSleep();
public Plan getPlan() {
return plan;
}
}
PlanABuilder,PlanBBuilder都担当具体建造者的角色
public class PlanABuilder extends AbstractBuilder {
@Override
public void arrangeMorning() {
// TODO Auto-generated method stub
plan.setMorningPlan("出发时间:8:00,目的地:白云山");
System.out.println("已制定好早上的计划");
}
@Override
public void arrangeAfternoon() {
// TODO Auto-generated method stub
plan.setAfternoonPlan("出发时间:12:00,目的地:长隆欢乐世界");
System.out.println("已制定好下午的计划");
}
@Override
public void arrangeNight() {
// TODO Auto-generated method stub
plan.setNightPlan("出发时间: 20:00 ,目的地:广州塔");
System.out.println("已制定好晚上的计划");
}
@Override
public void arrangeSleep() {
System.out.println("该计划不安排住宿");
}
}
public class PlanBBuilder extends AbstractBuilder {
@Override
public void arrangeMorning() {
// TODO Auto-generated method stub
plan.setMorningPlan("出发时间:8:15,目的地:大夫山");
System.out.println("已制定好早上的计划");
}
@Override
public void arrangeAfternoon() {
// TODO Auto-generated method stub
plan.setAfternoonPlan("出发时间:11:30,目的地:长隆欢乐世界");
System.out.println("已制定好下午的计划");
}
@Override
public void arrangeNight() {
// TODO Auto-generated method stub
plan.setNightPlan("出发时间: 20:00 ,目的地:广州塔");
System.out.println("已制定好晚上的计划");
}
@Override
public void arrangeSleep() {
System.out.println("晚上住宿在白天鹅宾馆");
}
}
Client类作为客户类,只需调用Director的consructPlan即可完成计划对象的创建
public class Client {
public static void main(String[] args) {
Director director = new Director(new PlanABuilder());
Plan p1 = director.constructPlan();
System.out.println("计划详情:" + p1);
director.setPlanBuilder(new PlanBBuilder());
Plan p2 = director.constructPlan();
System.out.println("计划详情:" + p2);
}
}
java.lang.StringBuilder中的建造者模式
StringBuilder类的继承和实现关系,如图:
Appendable接口定义了三个append方法,其担当抽象建造者的角色,定义了抽象方法。
public interface Appendable {
Appendable append(CharSequence csq) throws IOException;
Appendable append(CharSequence csq, int start, int end) throws IOException;
Appendable append(char c) throws IOException;
}
AbstractStringBuilder实现了Appendable接口的三个方法,AbstractStringBuilder类担当了具体建造者的角色,当由于其是抽象类,所以不能实例化。
abstract class AbstractStringBuilder implements Appendable, CharSequence {
//省略
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
return appendNull();
if (s instanceof String)
return this.append((String)s);
if (s instanceof AbstractStringBuilder)
return this.append((AbstractStringBuilder)s);
return this.append(s, 0, s.length());
}
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
}
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
//省略
}
StringBuilder即担当了指挥者角色,同时担当了具体的建造者的角色,还是产品对象。其建造方法是由其父类AbstractStringBuilder来实现,下面三个重载的append方法都是建造方法,只不过比较简单,只有一个方法调用。
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
//省略
@Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
@Override
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
}
//省略
与抽象工厂模式相比, 建造者模式返回一个组装好的完整产品 ,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。
如果将抽象工厂模式看成 汽车配件生产工厂 ,生产一个产品族的产品,那么建造者模式就是一个 汽车组装工厂 ,通过对部件的组装可以返回一辆完整的汽车。
参考:
1.4.建造者模式
2.设计模式 | 建造者模式及典型应用