首页 > 代码库 > 建造者模式
建造者模式
对于建造者模式,我们首先来说明建造者模式是用来干嘛的。建造模式一般用于创建复杂对象,这些复杂对象的构建过程是稳定的,但是内部的构件通常要面临比较复杂的变化。怎么来解释呢?我们利用《大话设计模式》中的例子来解释,创建一个胖子和一个瘦子,我们需要画出头、手、脚、身体这几个部分,最没水平的写法是写两个类,一个胖子类,一个瘦子类,这不像我们一门面向对象语言所写出来的代码。通常我们可能会抽象出一个创建人的接口,并有画出头、手、脚、身体这几个抽象方法,胖子、瘦子分别来实现这几个方法,但是我们还需要将这几个方法组装起来,建造者模式利用一个指挥者类来控制建造过程,但是集绕我们的建造过程是稳定的,我们是否可以在我们出来的创建人接口修改为抽象类,定义一个建造方法呢?咦,写到这个地方,我发现好像建造者模式是不是把问题复杂化了?我们来通过这两周方法来对比看看。
我们先来看看我们通常所做的方法来实现这个创建胖子、瘦子的需求:
第一种方法
创建人的抽象类:
1 package day_11_createPerson; 2 3 /** 4 * 创建人的抽象类 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public abstract class Person {10 public abstract void head();11 public abstract void arm();12 public abstract void leg();13 public abstract void body();14 15 public void createPerson(){16 head();17 arm();18 leg();19 body();20 }21 }
胖子、瘦子对于头等的建造细节由它们自己去实现,因为小人的建造过程是问题的,所以这里提供一个createPerson具体方法。
下面是胖子、瘦子的实现:
1 package day_11_createPerson; 2 3 /** 4 * 建造胖子 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class Fat extends Person {10 11 /* (non-Javadoc)12 * @see day_11_createPerson.Person#head()13 */14 @Override15 public void head() {16 System.out.println("创建胖子的头");17 }18 19 /* (non-Javadoc)20 * @see day_11_createPerson.Person#arm()21 */22 @Override23 public void arm() {24 System.out.println("创建胖子的手");25 }26 27 /* (non-Javadoc)28 * @see day_11_createPerson.Person#leg()29 */30 @Override31 public void leg() {32 System.out.println("创建胖子的脚");33 }34 35 /* (non-Javadoc)36 * @see day_11_createPerson.Person#body()37 */38 @Override39 public void body() {40 System.out.println("创建胖子的身体");41 }42 43 }
1 package day_11_createPerson; 2 3 /** 4 * 建造瘦子 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class Thin extends Person {10 11 /* (non-Javadoc)12 * @see day_11_createPerson.Person#head()13 */14 @Override15 public void head() {16 System.out.println("创建瘦子的头");17 }18 19 /* (non-Javadoc)20 * @see day_11_createPerson.Person#arm()21 */22 @Override23 public void arm() {24 System.out.println("创建瘦子的手");25 }26 27 /* (non-Javadoc)28 * @see day_11_createPerson.Person#leg()29 */30 @Override31 public void leg() {32 System.out.println("创建瘦子的脚");33 }34 35 /* (non-Javadoc)36 * @see day_11_createPerson.Person#body()37 */38 @Override39 public void body() {40 System.out.println("创建瘦子的身体");41 }42 43 }
客户端测试代码:
1 package day_11_createPerson; 2 3 /** 4 * @author turbo 5 * 6 * 2016年9月16日 7 */ 8 public class Main { 9 10 /**11 * @param args12 */13 public static void main(String[] args) {14 Fat fat = new Fat();15 fat.createPerson();16 17 Thin thin = new Thin();18 thin.createPerson();19 }20 21 }
第一种方法简单易懂,并且满足了我们了需求,那第二种利用建造者模式呢?
第二种方法
这里我们要实现一个Product类,这个额外的Product类是用来干嘛的呢?在这里我们的Product代表的就是创建出来的具体的胖子、瘦子“产品”。它由多个部件构成,也就是头、手、腿、身体。
1 package day_11_builder; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 /** 7 * 产品类——由多个部件组成 8 * @author turbo 9 *10 * 2016年9月16日11 */12 public class Product {13 private List<String> parts = new ArrayList<String>();14 15 public void add(String part){16 parts.add(part);17 }18 19 public void show(){20 for (String part : parts){21 System.out.println(part);22 }23 }24 }
接着我们同样有一个建造者,这里是接口,只负责提供创建人的头等的方法,建造过程不由建造者实现,而是由另一个类指挥者(Director)来实现。
1 package day_11_builder; 2 3 /** 4 * 建造者接口 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public interface Builder {10 void head();11 void arm();12 void leg();13 void body();14 Product getResult();15 }
我们来实现这个建造者接口:
1 package day_11_builder; 2 3 /** 4 * @author turbo 5 * 6 * 2016年9月16日 7 */ 8 public class FatBuilder implements Builder { 9 private Product product = new Product();10 11 /* (non-Javadoc)12 * @see day_11_builder.Builder#head()13 */14 @Override15 public void head() {16 product.add("创建胖子的头");17 }18 19 /* (non-Javadoc)20 * @see day_11_builder.Builder#arm()21 */22 @Override23 public void arm() {24 product.add("创建胖子的手");25 }26 27 /* (non-Javadoc)28 * @see day_11_builder.Builder#leg()29 */30 @Override31 public void leg() {32 product.add("创建胖子的腿");33 }34 35 /* (non-Javadoc)36 * @see day_11_builder.Builder#body()37 */38 @Override39 public void body() {40 product.add("创建胖子的身体");41 }42 43 /* (non-Javadoc)44 * @see day_11_builder.Builder#getResult()45 */46 @Override47 public Product getResult() {48 return product;49 }50 51 }
1 package day_11_builder; 2 3 /** 4 * 具体建造者2 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class ThinBuilder implements Builder {10 private Product product = new Product();11 12 /* (non-Javadoc)13 * @see day_11_builder.Builder#head()14 */15 @Override16 public void head() {17 product.add("创建瘦子的头");18 }19 20 /* (non-Javadoc)21 * @see day_11_builder.Builder#arm()22 */23 @Override24 public void arm() {25 product.add("创建瘦子的手");26 }27 28 /* (non-Javadoc)29 * @see day_11_builder.Builder#leg()30 */31 @Override32 public void leg() {33 product.add("创建瘦子的腿");34 }35 36 /* (non-Javadoc)37 * @see day_11_builder.Builder#body()38 */39 @Override40 public void body() {41 product.add("创建瘦子的身体");42 }43 44 /* (non-Javadoc)45 * @see day_11_builder.Builder#getResult()46 */47 @Override48 public Product getResult() {49 return product;50 }51 52 }
建造者方法中有一个getResult方法,返回一个Product类型,也就是返回一个具体的产品,具体的胖子还是瘦子。那么我们的建造过程去哪儿了呢?上面提到了由一个指挥者来指挥建造过程。
1 package day_11_builder; 2 3 /** 4 * 指挥者——指挥具体的建造过程 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class Director {10 public void construct(Builder builder){11 builder.head();12 builder.arm();13 builder.leg();14 builder.body();15 }16 }
建造者模式将建造过程和实现组件的具体细节相分离。客户端测试代码:
1 package day_11_builder; 2 3 /** 4 * 客户端测试 5 * @author turbo 6 * 7 * 2016年9月16日 8 */ 9 public class Main {10 public static void main(String[] args){11 Director director = new Director();12 Builder b1 = new FatBuilder();13 Builder b2 = new ThinBuilder();14 15 director.construct(b1);16 Product product1 = b1.getResult();17 product1.show();18 19 director.construct(b2);20 Product product2 = b2.getResult();21 product2.show();22 }23 }
这样我们就用建造者模式实现了上面创建一个胖子和瘦子的需求。
但是这两种方法到底有什么不同呢?第一种方法确实简单易懂。第二种方法将建造小人各个部分即Builder、具体小人Product、构建过程Director相互分离。到底是第一种方法简单易读好?还是第二种利用建造者模式好呢?(未完,待仔细分析)
建造者模式