随笔-126  评论-247  文章-5  trackbacks-0

Builder 模式 —— 建造者模式(又译成生成器模式的主要功能是构建复杂的产品,它是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

举个例子,打个生产电脑的比方,这里简单一点,假设生产电脑只需要 CUP、内存和显卡,现在需要生产宏基和戴尔两个品牌的电脑,不用设计模式的实现:

Acer.java

import java.util.ArrayList;
import java.util.List;
/**
 * -----------------------------------------
 * @描述  生产宏基笔记本电脑
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-4 <p>
 * -----------------------------------------
 
*/

public class Acer{

    
protected List<String> parts = new ArrayList<String>();
    
    
//生产CPU
    public void createCPU() {
        
        parts.add(
"CUP: Intel 酷睿i3 2350M");
    }


    
//生产内存
    public void createMemory() {

        parts.add(
"内存: 4GB DDR3 1333MHz");
    }


    
//生产显卡
    public void createDisplayCard() {

        parts.add(
"显卡: NVIDIA GeForce GT 520M");
    }

    
    
//显示产品信息
    public void show(){
        System.out.print(
"产品部件信息:");
        
for(String part : parts){
            System.out.print(part 
+ "\t");
        }

    }


}



Dell.java

import java.util.ArrayList;
import java.util.List;
/**
 * -----------------------------------------
 * @描述  生产戴尔笔记本电脑
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-4 <p>
 * -----------------------------------------
 
*/

public class Dell{

    
protected List<String> parts = new ArrayList<String>();

    
//生产CPU
    public void createCPU() {

        parts.add(
"CUP: Intel 酷睿i7 3612QM");
    }


    
//生产内存
    public void createMemory() {

        parts.add(
"内存: 8GB DDR3 1600MHz");
    }


    
//生产显卡
    public void createDisplayCard() {

        parts.add(
"显卡: NVIDIA GeForce GT 640M+Intel GMA HD 4000");
    }


    
//显示产品信息
    public void show(){
        System.out.print(
"产品部件信息:");
        
for(String part : parts){
            System.out.print(part 
+ "\t");
        }

    }


}



Client.java

/**
 * -----------------------------------------
 * @描述  客户端测试
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-4 <p>
 * -----------------------------------------
 
*/

public class Client {

    
private static Acer acer = new Acer();
    
private static Dell dell = new Dell();
    
    
public static void main(String[] args){

        
/**
         * 宏基
         
*/

        acer.createCPU();
        acer.createMemory();
        acer.createDisplayCard();
        acer.show();
        
        
/***************************************/
        System.out.println();
        
/***************************************/
        
       
/**
         * 戴尔
         
*/

        dell.createCPU();
        dell.createMemory();
        dell.createDisplayCard();
        dell.show();
    }

    
}



仔细观察一下上面的实现,不难发现,不管是生产何种品牌的笔记本,在实现的时候,它们的步骤基本上都是一样的,都是生产电脑相应的部件并添加都电脑里面,在生产不同品牌电脑

的时候,都会重复处理这几个步骤,但是明显的是,这几个步骤都是稳定的或者说是一样的,只是每个步骤的具体实现不一样或者说是变化的,如果将这些变化的部分抽取出来,也就是

说如果将处理过程与具体的步骤的实现分离开来的话,这样就能够复用这些处理过程,而且这样一来就能很容易的做到在不同品牌电脑之间切换生产。

使用 Builder 模式的实现,如图:


Product.java

package pattern.builder;

import java.util.ArrayList;
import java.util.List;
/**
 * -----------------------------------------
 * @描述  抽象产品
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public abstract class Product {

    
protected List<String> parts = new ArrayList<String>();
    
    
//添加部件
    public void add(String part){
        parts.add(part);
    }


    
//显示产品信息
    public void show(){
        System.out.print(
"产品部件信息:");
        
for(String part : parts){
            System.out.print(part 
+ "\t");
        }

    }

}



Acer.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  宏基笔记本
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class Acer extends Product{

    
//Do other things here
    
}



Dell.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  戴尔笔记本
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class Dell extends Product{

    
//Do other things here
    
}



Builder.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  抽象建造者
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public interface Builder {

    
//CUP
    public void buildCPU();
    
    
//内存
    public void buildMemory();
    
    
//显卡
    public void buildDisplayCard ();
    
    
//最终产品
    public Product getFinalResult();
    
}



AcerBuilder.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  宏基笔记本建造者
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class AcerBuilder implements Builder {

    
private Product product = new Acer();
    
    @Override
    
public void buildCPU() {
        
        product.add(
"CUP: Intel 酷睿i3 2350M");
    }


    @Override
    
public void buildMemory() {

        product.add(
"内存: 4GB DDR3 1333MHz");
    }


    @Override
    
public void buildDisplayCard() {

        product.add(
"显卡: NVIDIA GeForce GT 520M");
    }


    @Override
    
public Product getFinalResult() {
        
        
return product;
    }


}



DellBuilder.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  戴尔笔记本建造者
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class DellBuilder implements Builder {

    
private Product product = new Dell();
    
    @Override
    
public void buildCPU() {
        
        product.add(
"CUP: Intel 酷睿i7 3612QM");
    }


    @Override
    
public void buildMemory() {

        product.add(
"内存: 8GB DDR3 1600MHz");
    }


    @Override
    
public void buildDisplayCard() {

        product.add(
"显卡: NVIDIA GeForce GT 640M+Intel GMA HD 4000");
    }


    @Override
    
public Product getFinalResult() {
        
        
return product;
    }


}



Director.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  产品构建指导者
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class Director {

    
private Builder builder;
    
    
public Director(Builder builder){
        
this.builder = builder;
    }

    
    
public void construct(){
        
        builder.buildCPU();
        builder.buildMemory();
        builder.buildDisplayCard();
    }

}



Client.java

package pattern.builder;
/**
 * -----------------------------------------
 * @描述  客户端测试
 * @作者  fancy
 * @邮箱  fancydeepin@yeah.net
 * @日期  2012-8-5 <p>
 * -----------------------------------------
 
*/

public class Client {

    
private static Builder acerBuilder = new AcerBuilder(),
                                                dellBuilder 
= new DellBuilder();
    
    
public static void main(String[] args){
        
        System.out.print(
"宏基");
        Director director 
= new Director(acerBuilder);
        director.construct();
        Product product 
= acerBuilder.getFinalResult();
        product.show();
        
        
/***************************************/
        System.out.println();
        
/***************************************/
        
        System.out.print(
"戴尔");
        director 
= new Director(dellBuilder);
        director.construct();
        product 
= dellBuilder.getFinalResult();
        product.show();
    }

    
}



后台输出:

宏基产品部件信息:CUP: Intel 酷睿i3 2350M       内存: 4GB DDR3 1333MHz    显卡: NVIDIA GeForce GT 520M    
戴尔产品部件信息:CUP: Intel 酷睿i7 3612QM    内存: 8GB DDR3 1600MHz    显卡: NVIDIA GeForce GT 640M+Intel GMA HD 
4000


在这里,Acer 类和 Dell 类是空的,如果是这种情况,那么它们可以省略掉,如果 Product 也不是最终想要的,那么它也可以被省略掉,最终剩下的就只有 Director、Builder、

和具体的 Bulider 实现类。

在这里,Acer 类和 Dell 类是有关系的两个类,它们都是电脑的品牌之一,如果遇到两个或多个没有太多关系的类,假设 Acer 类代表电脑,Dell 类代表汽车,很明显,Acer 类和

Dell 类就不应该再有共同的父类,也就是这种情况下,Product 这个抽象类不存在了,这时候问题就来了,那么 Builder 接口的规定的 getFinalResult() 方法的返回值怎么确定呢??

如果它的返回值
类型是 Acer,那么 DellBuilder 类就会有问题,如果它的返回值类型是 Dell,那么 AcerBuilder 类就会有问题;

很明显,这是由于类型不能正确匹配引起的,如果是这种情况,可以将 Product 设计成标识接口(空接口,接口里面没有规定任何行为方法),再让这些没有相互关系的具体产品类

都去实现这个接口,那么 Builder 接口里面规定的 getFinalResult() 方法的返回值类型依然是 Product 类型,这样一来问题就解决了。


  
posted on 2012-08-05 14:03 fancydeepin 阅读(5839) 评论(4)  编辑  收藏

评论:
# re: java 建造者模式(Builder) 2013-02-20 17:35 | rexue
一看就懂,太好太详细了  回复  更多评论
  
# re: java 建造者模式(Builder) 2013-04-18 14:28 | Willy
谢谢您!  回复  更多评论
  
# re: java 建造者模式(Builder) 2013-10-11 10:58 | 经典小笑话
看了几篇相关的,终于第一篇让我明白了。因为有一个"不用设计模式的实现",谢谢了,呵~  回复  更多评论
  
# re: java 建造者模式(Builder) 2016-08-02 11:41 | Nimo
多谢,讲的很清楚  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问