Chap3:建立型设计模式————工厂方法设计模式(上)

建立型设计模式

包括如下五种:php

  • 抽象工厂css

  • 生成器html

  • 工厂方法设计模式

  • 原型编辑器

  • 单例this

咱们选择工厂方法和原型模式做为将用PHP实现的建立型设计的例子
工厂方法模式是这5个设计模式中惟一的一种类设计模式
原型模式属于对象类模式,可使用PHP_clone方法实现。首先基于原型实例化(建立)一个对象,而后由这个实例化对象进一步克隆其余对象
使用建立型模式时,最有意思的是,当程序和系统愈来愈依赖于对象组合而不是依赖于类继承时,建立型模式中的程序变成由对象构成的系统,而对象又由其余对象组合而成,因此任何单个对象的建立都不该该依赖于建立者spa

工厂方法模式

概念:工厂方法模式就是要建立某种东西,对于工厂方法模式,要建立的东西是一个产品,这个产品与建立它的类之间不存在绑定,为了保持这种松耦合,客户会经过一个工厂发出请求,再由工厂建立所请求的产品。利用工厂方法模式,请求者发出请求,而不具体建立产品。
什么时候使用:若是实例化对象的子类可能变化,就要使用工厂方法模式
Why:对象的数目和类型都是未知的,一个类没法预计它要建立的对象数目,因此你不但愿类与它要建立的类紧密绑定设计

案例模型:
clipboard.pngcode

步骤:orm

第一步是创建工厂:Creator接口

<?php
//Creator.php
abstract class Creator{
    protected abstract function factoryMethod();
    public function startFactory(){
        $mfg = $this->factoryMethod();
        return $mfg;
    }
}
?>

注意到,伪代码注释提示startFactory()方法须要返回一个产品(product),在实现中startFactory()但愿factoryMethod()返回一个产品对象,因此,factoryMethod()的具体实现要构建并返回由一个按Product接口实现的产品对象

下面有两个工厂类扩展了Creator,并实现了factoryMethod()方法,factoryMethod()实现经过一个Product方法(getProperties())返回一个文本或图像产品,TextFactory和GraphicFactory实现中加入了这些内容

<?php
//TextFactory.php
include_once('Creator.php');
include_once('TextProduct.php');
class TextFactory extends Creator{
    protexted function factoryMethod(){
        $product = new TextProduct();
        return ($product->getProperties());
    }
}
?>
<?php
//TextFactory.php
include_once('Creator.php');
include_once('GraphicProduct.php');
class GraphicFactory extends Creator{
    protexted function factoryMethod(){
        $product = new GraphicProduct();
        return ($product->getProperties());
    }
}
?>

工厂方法设计模式中的第二个接口是Product。因为这是第一个实现,也是最简单的实现,全部文本和图像属性都只实现一个方法getProperties():创建方法而无属性,咱们能够明确想要用这个方法作什么(好比能够有个返回值),只要方法名和可见性与签名一致就不会有问题

<?php
//Product.php
interface Product{
    public function getProperties();
}
?>

能够利用这个实现,使得同一个方法getProperties()多态,分别返回图像和文字,以下所示

<?php
//TextProduct.php
include_once('Prouduct.php');
class TextProduct implements Product{
    private $mfgProduct;
    public function getProperties(){
        $this->mfgProduct = "This is a Text<br";
        return $this->mfgProduct;
    }
}
?>
<?php
//Graphic.php
include_once('Product.php');
class GraphicProduct implements Product{
    private $mfgProduct;
      public function getProperties(){
        $this->mfgProduct = "This is a Graphic<br>";
        return $this->mfgProduct;
    }
}
?>

上面你看到的This is a Graphic以及This is text,能够替换成你想放入的其它东西,工厂设计会建立这个对象,并把它返回给Client来使用。
这两个工厂和产品分别覆盖了抽象方法,来建立两个不一样的工厂和产品,它们都符合所实现的接口

客户
这个模式最后一个参与者是隐含的(上面模型图中颜色较淡的框):客户。咱们并不但愿Client类直接作出产品请求。实际上,咱们但愿可以经过Creator接口作出请求,这样一来,若是之后咱们增长产品或者工厂,客户能够作一样的请求来获得更多类型的产品,而不会破坏这个应用

<?php
//Client.php
include_once('GraphicFactory.php');
include_once('TextFactory.php');
class Client{
    private $someGraphicObject;
    private $someTextObject;
    public function __construct(){
        $this->someGraphicObject = new GraphicFactory();
        echo $this->someGraphicObject->startFactory();
         $this->someTextObject = new TextFactory();
        echo $this->someTextObject->startFactory();
    }
}
$worker = new Client();
?>

注意Client对象并无向产品直接作出请求,而是经过工厂来请求,重要的是,客户并不实现产品特性,而留给产品实现来体现。


在本章有个例子,是对上面代码的改进,也能够称做是在工厂中修改产品,可是本猿觉得,例子彷佛举的不是很好,它把Html代码嵌套在php代码中,放在了产品类下的getProperties方法中,以供客户调用的时候返回,因此我我的以为这种方法不是很好,一大段代码放在php中,也不方便编辑器编辑。设计模式是为了加快开发速度,这样的方法我拔苗助长。做者是专家,可能也有出于其它考虑。不过里面有一个观点我仍是赞成的,其中有一个辅助类的观点。
所谓辅助类,就是把一些任务给一个单独的对象来处理,而不是结合到某个参与者中。相似地,若是须要重用一组HTML标记,能够把它们打包到另外一个对象中以便重用。下面是一个例子

<?php
class FormatHelper{
    private $topper;
    private $bottom;
    public function addTop(){
        $this->topper = "<!doctype html><html><head>
        <link rel='stylesheet' type='text/css' href='products.css'/>       
        <meta charset='UTF-8'>
        <title>Map Factory</title>
        </head> <body>";
        return $this->topper;
    }
    public function closeUp(){
        $this->bottom = "</body></html>";
        return $this->bottom;
    }
}
?>

增长新产品和参数化请求

clipboard.png

上图与以前的类图不一样,它们完成一样的目标,不过它们的实现有所不一样。这就是参数化工厂方法设计模式(上图)与通常的工厂方法设计模式(原类图)的主要区别之一,即客户包含工厂和产品的引用。在参数化请求中,Client类必须指定产品,而不仅是产品工厂,factoryMethod()操做中的参数是由客户传入的一个产品,因此客户必须指出它想要的具体产品,不过,这个请求仍然经过Creator接口发出,因此,尽管客户包含一个产品引用,但经过Creator,客户仍与产品分离

一个工厂多个产品

对于大多数请求,参数化工厂方法更为简单,由于客户只须要处理一个具体工厂,工厂方法操做有一个参数,指示须要建立的产品。而在原来的设计中,每一个产品都有本身的工厂,不须要另外传递参数,产品实现依赖于各个产品的特定工厂。

要从参数化工厂方法设计模式实现多个产品,只需使用Product接口实现多个具体产品,另外,因为具体产品要同时包含文本和图像,因此在这个例子中,并非分别有这两个单独的产品,能够创建一个类,将文本和图像做为一个赞成的实体来处理,这并不违反单一职责原则,即每一个类应当只有一个职责。对于这个类来讲,这个单一职责就是显示描述一个区域的文本和图像

新工厂

新工厂与原来的工厂相似,不过它们还包含一个参数和代码提示。

<?php
//Creator.php
abstract class Creator{
    protected abstract function factoryMethod(Product $product);
    
    public function doFactory($productNow){
        $countryProduct = $productNow;
        $mfg = $this->factoryMethod($countryProduct);
        return $mfg;
    }
}
?>

新的Creator抽象类中能够看到,factoryMethod()和startFactory操做都须要一个参数。另外代码提示只是了一个Product对象,而不是Prodcut一个特定实现,因此能够接受Product的任何具体实例,下面来看看具体的建立者CountryFactory

<?php
//CountryFactory.php
include_once('Creator.php');
inlcude_once('Product.php');
class CountryFactory extends Creator{
    private $country;
    protected function factoryMethod(Product $product){
        $this->country = $product;
        return ($this->country->getProperties());
    }
}
?>

这个具体建立者包含一个私有变量$country,其中包含客户请求的特定产品,它再使用Product方法getProperties()将产品返回给客户

与试图让任意数目的类和对象都保持不变相比,保持接口不变要容易得多。正是由于这个缘由,使用工厂方法模式能够简化复杂的建立过程,关键就在于它在维持一个公共接口

本文参考书籍:《Learnig PHP设计模式》第2部分第5章

相关文章
相关标签/搜索