首页 > 代码库 > 建造者模式

建造者模式

对于建造者模式,我们首先来说明建造者模式是用来干嘛的。建造模式一般用于创建复杂对象,这些复杂对象的构建过程是稳定的,但是内部的构件通常要面临比较复杂的变化。怎么来解释呢?我们利用《大话设计模式》中的例子来解释,创建一个胖子和一个瘦子,我们需要画出头、手、脚、身体这几个部分,最没水平的写法是写两个类,一个胖子类,一个瘦子类,这不像我们一门面向对象语言所写出来的代码。通常我们可能会抽象出一个创建人的接口,并有画出头、手、脚、身体这几个抽象方法,胖子、瘦子分别来实现这几个方法,但是我们还需要将这几个方法组装起来,建造者模式利用一个指挥者类来控制建造过程,但是集绕我们的建造过程是稳定的,我们是否可以在我们出来的创建人接口修改为抽象类,定义一个建造方法呢?咦,写到这个地方,我发现好像建造者模式是不是把问题复杂化了?我们来通过这两周方法来对比看看。

我们先来看看我们通常所做的方法来实现这个创建胖子、瘦子的需求:


 

第一种方法

创建人的抽象类:

 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相互分离。到底是第一种方法简单易读好?还是第二种利用建造者模式好呢?(未完,待仔细分析)

建造者模式