构造者模式用于创建一个包含多个组成部分的复杂对象,可以返回一个完整的产品对象给用户。建造者模式关注该复杂对象时如何一步一步创建而成的,对于用户而言,无需知道创建过程和内部组成细节,只需直接使用创建好的完整对象即可。
模式动机:
无论在现实生活中还是在软件系统中,都存在一些复杂的对象,他们拥有多个组成部分,如汽车,他包括方向盘,车轮,发送机等各种部件,而对于大多数用户而言,无需知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一台完整的汽车,如图:
在软件开发中,也存在大量类似汽车一样的复杂对象,他们拥有一系列成员属性,这些成员属性有些是引用类型的成员对象,而且在这些对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用,例如,一封电子邮件包括发件人,收件人,主题,内容,附件等,没有收件人则不能构造。此时,复杂对象相当于一台有待构造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无需关心该对象所包含的属性以及他们的组装方式,这就是建造者模式的动机。
模式定义:
建造者模式builder pattern:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。构造者模式是一步一步创建一个复杂的对象,它允许用户只通过复杂对象的类型和内容就可以构建他们,用户不需要知道内部的具体细节。建造者模式属性对象创建型模式。
definition
Separate the construction of a complex object from its representation so that the same construction process can create different representations. |
Product:他包含多个组成部件,具体构建者创建该产品的内部表示并定义它的装配过程。
Builder:为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX()方法,他们用于创建复杂对象的各个部件,另一类方法是getResult()方法,用于返回复杂对象。
concreteBuilder:实现了builder的接口。也可以提供一个方法返回创建好的复杂产品对象。
Director:
指挥者又称导演雷,他负责安装对象建造次序,。
个人感悟:
如果细看,会发现builder pattern和策略模式很是相似,策略模式也是定义了一个接口的几种实现,然后调用时改变接口所指向的具体实例,只不过builder属于对象创建型模式,策略模式属于对象行为型模式。
实例:
建造者模式用于描述KFc如何创建套餐:套餐是一个复杂对象,他一般包含主食(如汉堡,鸡肉卷等)和饮料(如果汁、可乐等)等组成部分;不同的套餐有不同的组成部分,而KFC 的服务员可以根据顾客的要求,一步一步的装配这些组成部分,构造一个完整的套餐,然后返回给客户。
代码:
Product类:
public class Meal { //food 和drink是部件 private String food; private String drink; public String getFood() { return food; } public void setFood(String food) { this.food = food; } public String getDrink() { return drink; } public void setDrink(String drink) { this.drink = drink; } public String toString() { return (food+drink); } }
Builder类:
public abstract class MealBuilder { protected Meal meal=new Meal(); public abstract void buildFood(); public abstract void bulidDrink(); public Meal getMeal() { return meal; } }
这里的builder类有Product类的引用,子类就继承了Product。更上面的uml图中子类含有Procut类的引用不同。
具体构造者:
public class SubMealBuilderA extends MealBuilder{ @Override public void buildFood() { meal.setFood("一个鸡腿堡"); } @Override public void bulidDrink() { meal.setDrink("一杯可乐"); } }
public class SubMealBuilderB extends MealBuilder{ @Override public void buildFood() { meal.setFood("一个鸡肉卷"); } @Override public void bulidDrink() { meal.setDrink("一杯果汁"); } }
Director类:
public class KFCWaiter { private MealBuilder mb; public void setMealBuilder(MealBuilder mb) { this.mb=mb; } public Meal construct() { mb.buildFood(); mb.bulidDrink(); return mb.getMeal(); } }
测试类:
public class TestMain { public static void main(String[] args) { MealBuilder mb=new SubMealBuilderA(); KFCWaiter waiter=new KFCWaiter(); waiter.setMealBuilder(mb); Meal meal=waiter.construct(); System.out.println(meal.getFood()); System.out.println(meal.getDrink()); mb=new SubMealBuilderB(); waiter.setMealBuilder(mb);//一定要有这句,否则还是前面的 Meal meal2=waiter.construct(); System.out.println(meal2); System.out.println(meal2.getFood()); System.out.println(meal2.getDrink()); } }
一个鸡腿堡
一杯可乐
一个鸡肉卷一杯果汁
一个鸡肉卷
一杯果汁
可以看出,跟换具体构造者无须修改。
参考:http://www.dofactory.com/Patterns/PatternBuilder.aspx
建造者模式与工厂模式的区别
我们可以看到,建造者模式与工厂模式是极为相似的,总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。
与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。