设计模式(三)建造者模式Builder(创建型)

1. 概述

       在软件开发的过程中,当遇到一个“复杂的对象”的创建工作,该对象由一定各个部分的子对象用一定的算法构成,由于需求的变化,复杂对象的各个部分经常面临剧烈的变化,但将它们组合在一起的算法相对稳定。

       例子1:买肯德基

       典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。

       1.jpg

       客户端:顾客,想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
       指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
       建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
       产品角色:最后的套餐,所有的东西放在同一个盘子里面。

        例子2:计算工资:工资的计算一般是:底薪+奖金-税。但底薪分为一级8000、二级6000、三级4000三个等级。根据岗位不同奖金的发放也不一样,管理及日常事务处理岗位(A类)每月根据领导及同事间的评议得分计算奖金,销售岗位(B类)则根据销售额发放提成。税金则根据奖金和底薪的数额进行计算。由此看出该工资的计算方式是比较稳定的构建算法,但对工资的每一部分都会根据不同的情况产生不同的算法,如何将客户端与变化巨烈的底薪、奖金和税金计算方式分离呢,这也比较适合用建造者模式。

2 . 问题

我们如何应对这种变化,如何提供一种“封装机制”来隔离“复杂对象的各个部”的变化,从而保持系统中的“稳定构建算法”而不随需求的变化而变化?

3. 解决方案

建造者模式: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

4. 适用性

在以下情况使用Builder模式

•当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

•当构造过程必须允许被构造的对象有不同的表示时。

5. 结 构

此模式结构如下页上图所示。

2.jpg

6. 构建模式的组成

• 抽象建造者角色(Builder):为创建一个Product对象的各个部件指定抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此角色规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
• 具体建造者(ConcreteBuilder)

1)实现Builder的接口以构造和装配该产品的各个部件。即实现抽象建造者角色Builder的方法。

2)定义并明确它所创建的表示,即针对不同的商业逻辑,具体化复杂对象的各部分的创建

3)  提供一个检索产品的接口

4)   构造一个使用Builder接口的对象即在指导者的调用下创建产品实例

指导者(Director):调用具体建造者角色以创建产品对象的各个部分。指导者并没有涉及具体产品类的信息,真正拥有具体产品的信息是具体建造者对象。它只负责保证对象各部分完整创建或按某种顺序创建。

产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。

7. 效果

Builder模式的主要效果:

1 ) 它使你可以改变一个产品的内部表示 Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。

2) 它将构造代码和表示代码分开 Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不出现在Builder接口中的。每个Concrete Builder包含了创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。

3 ) 它使你可对构造过程进行更精细的控制 Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构建过程,从而能更精细的控制所得产品的内部结构。

8. 实现:

指导者:收银员

<?php  
/** 
 * 指导者:收银员 
 * 
 */  
class DirectorCashier  
{  
    /** 
     * 收银餐馆员工返回的食物 
     * 
     */  
    public function buildFood(Builder $builder) {  
        $builder->buildPart1();  
        $builder->buildPart2();  
    }  
}

 抽象建造者:

/** 
 * 抽象建造者 
 * 
 */  
abstract class Builder  
{  
    /** 
     * 创建产品的第一部分 
    */  
    public abstract function buildPart1();  
  
    /** 
     *  
     * 创建产品的第二部分 
    */  
    public abstract function buildPart2();  
      
    /** 
     *  
     *  返回产品 
    */  
    public abstract function getProduct();  
}

具体建造者类:

/** 
 * 具体建造者类:餐馆员工,返回的套餐是:汉堡两个+饮料一个 
 * 
 */  
 class ConcreteBuilder1 extends Builder  
 {  
    protected $_product = null;//产品对象  
    function __construct(){  
        $this->_product = new Product();  
    }  
  
    /** 
     * 创建产品的第一部分::汉堡=2 
     */  
    public  function buildPart1()  
    {  
        $this->_product->add('Hamburger',2);  
    }  
    /** 
     *  
     * 创建产品的第二部分: 
     */  
    public  function buildPart2()  
    {  
        $this->_product->add('Drink', 1);  
    }  
    /** 
     * 返回产品对象 : 
     *  
     */  
    public function  getProduct()  {  
        return  $this->_product;  
    }  
 }  
  
/** 
 * 具体建造者类:餐馆员工,汉堡1个+饮料2个 
 * 
 */  
 class ConcreteBuilder2 extends Builder  
 {  
    protected $_product = null;//产品对象  
    function __construct(){  
        $this->_product = new Product();  
    }  
  
    /** 
     * 创建产品的第一部分:汉堡 
     */  
    public  function buildPart1()  
    {  
        $this->_product->add('Hamburger', 1);  
    }  
    /** 
     *  
     * 创建产品的第二部分:drink=2 
     */  
    public  function buildPart2()  
    {  
        $this->_product->add('Drink', 2);  
    }  
    /** 
     * 返回产品对象 : 
     *  
     */  
    public function  getProduct()  {  
        return  $this->_product;  
    }  
 }

产品类:

/** 
  * 产品类 
  */  
 class Product  
 {  
    public $products = array();  
    /** 
     * 添加具体产品 
     */  
    public function add($name,  $value) {  
        $this->products[$name] = $value;  
    }  
    /** 
     * 给顾客查看产品 
     */  
    public function showToClient()  
    {  
        foreach ($this->products as $key => $v) {  
            echo $key , '=' , $v ,'<br>';  
        }  
    }  
 }
  1. 客户程序:  

<pre name="code" class="php"> //客户程序  
 class Client  
 {  
    /** 
     * 顾客购买套餐 
     * 
     */  
    public  function buy($type) {  
        //指导者,收银员  
         $director  = new DirectorCashier();   
         //餐馆员工,收银员  
         $class = new ReflectionClass('ConcreteBuilder' .$type );  
         $concreteBuilder  = $class->newInstanceArgs();  
         //收银员组合员工返回的食物  
         $director->buildFood($concreteBuilder);  
         //返回给顾客  
         $concreteBuilder->getProduct()->showToClient();  
    }  
 }  
   
 //测试  
 ini_set('display_errors', 'On');  
 $c = new Client();  
 $c->buy(1);//购买套餐1  
 $c->buy(2);//购买套餐1</pre>  
<pre></pre>  
<pre></pre>  
<pre></pre>

 

9. 建造者模式的优点

       首先,建造者模式的封装性很好。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。

       其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。

10. 建造者模式与工厂模式的区别

      我们可以看到,建造者模式与工厂模式是极为相似的,总体上,建造者模式仅仅只比工厂模式多了一个“导演类”的角色。在建造者模式的类图中,假如把这个导演类看做是最终调用的客户端,那么图中剩余的部分就可以看作是一个简单的工厂模式了。

      与工厂模式相比,建造者模式一般用来创建更为复杂的对象,因为对象的创建过程更为复杂,因此将对象的创建过程独立出来组成一个新的类——导演类。也就是说,工厂模式是将对象的全部创建过程封装在工厂类中,由工厂类向客户端提供最终的产品;而建造者模式中,建造者类一般只提供产品类中各个组件的建造,而将具体建造过程交付给导演类。由导演类负责将各个组件按照特定的规则组建为产品,然后将组建好的产品交付给客户端。

11. 总结

      建造者模式与工厂模式类似,他们都是建造者模式,适用的场景也很相似。一般来说,如果产品的建造很复杂,那么请用工厂模式;如果产品的建造更复杂,那么请用建造者模式。

转自:http://blog.csdn.net/hguisu/article/details/7518060

原创文章,作者:s19930811,如若转载,请注明出处:http://www.178linux.com/2947

(0)
上一篇 2015-06-25 10:08
下一篇 2015-06-25 10:12

相关推荐

  • 我的第一篇博客

        对于一个连日记都懒得写的人来说,写博客博客还真是一个难题。但是为了能让自己有所进步有所提高、更是为了记录自己逐步成长的过程,还是下定决心记录下在接下来的日子里的点点滴滴。当然,这点点滴滴指的是 —— 知识     我想刚学linux的新手眼里除了图形化就只有黑白两种颜色了吧!但是为了提高自己…

    Linux干货 2017-07-15
  • grep基本正则表达式以及扩展正则表达式

    基本正则表达式: grep:Globel serach REgular expression and print out the line 作用:文本搜索工具,根据用户指定的“模式(过滤条件)”对目标文本逐行进行匹配检查,打印匹配到的行 模式:由正则表达式的元字符及文本字符所编写出的过滤条件 grep选项:       &nbs…

    Linux干货 2016-08-08
  • 第一周作业

    1、描述计算机的组成及其功能 答:计算机主要有5大组件构成: 1) 计算器:用户数据计算,主要是指CPU 2) 控制器:用于控制数据流或者指令流,控制计算机系统的各个组件的协同工作以及信息的流动,如各种控制芯片(南桥,北桥等) 3) 存储器:用户数据的存放,如内存 4) 输入设备:如键盘,鼠标等 5) 输出设备:如显示器,外置的存储设备( 硬盘,光…

    Linux干货 2016-10-30
  • OPENSSL加密技术及私有CA的搭建

    加密方式有对称加密 非对称加密 单向加密 对称加密:     加密和加密都用同一个对称密钥,但是,这种加密方法存在一定问题,就是密钥传输时,容易被盗窃。还有密钥管理困难,对称加密的方法:DES、AES、Blowfish、Twofish、IDEA、RC6、CAST5。   非对称加密: 公钥…

    Linux干货 2015-08-17
  • 用户权限管理及课后作业

    一.权限对目录、文件的意义 文件 r 可用文件查看类工具获取文件内容 w 可以修改文件内容(包括清空) x 可执行该文件 [root@localhost testdir]# cat zzz i am fine  thank you [root@localhost testdir]…

    Linux干货 2016-08-08
  • apache编译安装

    apache是什么:     Apache是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上,由于其跨平台和安全性被广泛使用,是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充,将Perl/Python等解释器编译到服务器中。同时Apache音译为阿帕奇,是北美印第安…

    Linux干货 2016-08-24