快速业务通道

php教程:php设计模式介绍之工厂模式

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-15
  • 这样很难单独测试和证实连接对象的状态。
  • 使用工厂设计模式,代码将得到很大的改进:

    class Product {
    function getList() {
    $db =& $this->_getConnection();
    //...
    }
    function &_getConnection() {
    return new MysqlConnection(DB_USER, DB_PW, DB_NAME);
    }
    }

    先前的类中存在很多调用new MysqlConnection(DB_USER,  DB_PW,  DB_NAME)的方法,现在都被集中到的_getConnection()方法上。

    下面是工厂的另一种变化,你静态地调用了一个工厂类:

    class Product {
    function getList() {
    $db =& DbConnectionBroker::getConnection();
    //...
    }
    }
    class DbConnectionBroker {
    function &getConnection() {
    return new MysqlConnection(DB_USER, DB_PW, DB_NAME);
    }
    }

     这里DbConnectionBroker::getConnection()产生的效果和前面的一样 ,但这样却很有好处: 我们不必在每个需要连接数据库的类中加入调用new MysqlConnection(DB_USER , DB_PW, DB_NAME)的方法。

    当然另一种变化就是引用一个外部工厂对象的资源,和这个对象定义了数据库连接的参数:

    class Product {
    var php教程:php设计模式介绍之工厂模式 - 凌众科技

    快速业务通道

    php教程:php设计模式介绍之工厂模式

    作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-15
    content

    凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

    分享到: 更多

    Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

    地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

    电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

    《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号

    db_maker;
    function setDbFactory(&$connection_factory) {
    $this->_db_maker =& $connection_factory;
    }
    function getList() {
    $db =& $this->_db_maker->getConnection();
    //...
    }
    }

    最后,一个工厂可以用一个函数合理的组织,然后实现:

    function &make_db_conn() {
    return new MysqlConnection(DB_USER, DB_PW, DB_NAME);
    }
    class Product {
    function getList() {
    $bar =& make_db_conn();
    //...
    }
    }

    下面是一个工厂的理想化执行的 UML 类图:

    例子:增加一些颜色

    让我们更深入工厂模式吧。继续如前,先建立一个能为本章节的其它部分持续举例说明的简单类。 这是一个输出十六进制的HTML RGB Color类,包括了R, G, 和 B三个属性(在构造对象的时候引入)和 getRgb()方法,getRgb()的作用是返回一个十六进制颜色的字符串。

    和以前一样,我们按照测试驱动开发(TDD)的方法:写一个测试,再写一段代码满足该测试,如果需要,反复下去。

    下面是一个非常简单的起始测试:

    function TestInstantiate() {
    $this->assertIsA($color = new Color, ‘Color’);
    $this->assertTrue(method_exists($color, ‘getRgb’));
    }

    为了满足这个测试,你可以设计这样一个类。测试看起来有点像伪代码:

    class Color {
    function getRgb() {}
    }

    ( 这个Color类也许看起来像处于娃娃阶段, 但是 TDD是一个反复的过程。 代码非常少,当需要的时候:你开始有了新的想法或者想精确的执行代码时,可以增加的。)

    接下来, 当颜色对象被建立时,getRgb() 方法应该返回以红色,绿色,和蓝色的十六进制字符串。 用一个测试说明一下:

    function TestGetRgbWhite() {
    $white =& new Color(255,255,255);
    $this->assertEqual(‘#FFFFFF’, $white->getRgb());
    }

    每个 TDD, 你写最简单的可行的代码来满足测试, 并不需要满足人的审美观或者代码的正确执行。

    下面是最简单的,能够通过测试的代码:

    class Color {
    function getRgb() { return ‘#FFFFFF’; }
    }

    这个Color类不是令人十分满意, 但是它确实表现了逐渐增加的过程。

    下一步,让我们增加一个额外的测试使这个Color类的的确确地执行并返回正确的信息:

    function TestGetRgbRed() {
    $red =& new Color(255,0,0);
    $this->assertEqual(‘#FF0000’, $red->getRgb());
    }

    这个Color类必须改变什么呢? 首先必须把红色,绿色,和蓝色的值储存在三个变量里,然后在调用一个方法把十进制数转化为十六进制数。按照这个要求执行的代码可以写作:

    class Color {
    var $r=0;
    var $g=0;
    var $b=0;
    function Color($red=0, $green=0, $blue=0)
    {
    $this->r =$red;
    $this->g = $green;
    $this->b = $blue;
    }
    function getRgb() {
    return sprintf(‘#%02X%02X%02X’, $this->r, $this->g, $this->b);
    }
    }

    这个构造非常简单: 先收集红色,绿色,和蓝色的数值,然后储存在变量中, getRgb() 方法使用 sprintf() 函数将十进制数转换成十六进制数。

    为了对代码充满更多的信心, 你可以用较多的数值来测试它。 这一个测试可以用以下代码实现:

    function TestGetRgbRandom() {
    $color =& new Color(rand(0,255), rand(0,255), rand(0,255));
    $this->assertWantedPattern(
    ‘/^#[0-9A-F]{6}$/’,
    $color->getRgb());
    $color2 =& new Color($t = rand(0,255), $t, $t);
    $this->assertWantedPattern(
    ‘/^#([0-9A-F]{2})\1\1$/’,
    $color2->getRgb());
    }

    注:assertWantedPattern
    assertWantedPattern() 作用是:使它的第二个叁数匹配第一个参数,第一个参数是正则表达式。如果匹配,这个测试就通过; 否则不通过。
    由于assertWantedPattern()具有进行正确的正则表达式匹配的功能,所以常被用作测试。

    所有这些测试Color类功能的行为都在正常和期望的环境下实现的。但是每一个设计精良的类都必须考虑边界情况。例如, 被送入构造器执行的数值如果是负数,或者大于255的数值,或者根本不是数值,结果会出现什么呢?一个好的类定义应该适应测试中的多种边界情况。

    function testColorBoundaries() {
    $color =& new Color(-1);
    $this->assertErrorPattern(‘/out.*0.*255/i’);
    $color =& new Color(1111);
    $this->assertErrorPattern(‘/out.*0.*255/i’);
    }

    注:assertErrorPattern
    assertErrorPattern() 作用是:将产生的php错误进行正确的正则表达式匹配。如果这个错误不匹配指定的模式, 将不通过测试。
    在那些测试的基础上,Color类将得到更进一步改进:

    class Color {
    var $r=0;
    var $g=0;
    var $b=0;
    function Color($red=0, $green=0, $blue=0) {
    $red = (int)$red;
    if ($red < 0 || $red > 255) {
    trigger_error(“color ‘$color’ out of bounds, “
    .”please specify a number between 0 and 255”);
    }
    $this->r = $red;
    $green = (int)$green;
    if ($green < 0 || $green > 255) {
    trigger_error(“color ‘$color’ out of bounds, “
    .”please specify a number between 0 and 255”);
    }
    $this->g = $green;
    $blue = (int)$blue;
    if ($blue < 0 || $blue > 255) {
    trigger_error(“color ‘$color’ out of bounds, “
    .”please specify a number between 0 and 255”);
    }
    $this->b = $blue;
    }
    function getRgb() {
    return sprintf(‘#%02X%02X%02X’, $this->r, $this->g, $this->b);
    }
    }

    这个代码通过了测试, 但是这种 " 剪切和粘贴 " 的风格有点使人厌倦。 在 TDD,一个经验法则就是将编码最简单的实现,如果你两次需要相同的代码,可以将其改进,但不要复制代码。 然而你往往需要三次或三次以上的一样代码。 因此我们可以提取一个方法即重构实现这个工作。

    注:重构 - 提取方法
    当你的代码中有两个或者两个以上部分的代码相似的时候, 可以将它们提取出来成为一个独立的方法,并按它的用途命名。当你的类的方法代码中频频出现相同的成分,提取代码作为一个方法是非常有用的。

    class Color {
    var $r=0;
    var $g=0;
    var $b=0;
    function Color($red=0, $green=0, $blue=0) {
    $this->r = $this->validateColor($red);
    $this->g = $this->validateColor($green);
    $this->b = $this->validateColor($blue);
    }
    function validateColor($color) {
    $check = (int)$color;
    if ($check < 0 || $check > 255) {
    trigger_error(“color ‘$color’ out of bounds, “
    .”please specify a number between 0 and 255”);
    } else {
    return $check;
    }
    }
    function getRgb() {
    return sprintf(‘#%02X%02X%02X’, $this->r, $this->g, $this->b);
    }
    }

    创建工厂来简化对象的创建过程

    让我们为Color类增加一个工厂,使得建立新的实例更简单。增加一个可以命名颜色的方法,这样就可以不记颜色数值,只需要记住自己喜欢的颜色名字。

    工厂对象或函数不一定都要被命名为 “工厂”。 当你读代码时,工厂是显而易见的。 相反的,它的名字最好取得有意义,这样可以反映出它解决了什么问题。

    在这个代码例子中, 我要叫它CrayonBox颜色工厂。静态的方法CrayonBox::getColor()引入命名颜色的字符串后,返回一个带有相应颜色属性的Color类。

    下面的例子就可以测试这一点:

    function TestGetColor() {
    $this->assertIsA($o =& CrayonBox::getColor(‘red’), ‘Color’);
    $this->assertEqual(‘#FF0000’, $o->getRgb());
    $this->assertIsA($o =& CrayonBox::getColor(‘LIME’), ‘Color’);
    $this->assertEqual(‘#00FF00’, $o->getRgb());
    }

     通过这个测试,我们发现每个返回的对象都是一个实例化的Color类,getRgb() 方法也返回了正确的结果。第一种情况是以“red”都是小写测试,第二种情况是以“LIME”都是大写测试,这样可以测试代码的通用性。

    保险起见, 我们再对其进行另外的测试,探究那些不合法的边界情况。TestBadColor() 方法的作用是:用一个不存在的颜色名字引发一个包含这个颜色名字的php错误,并返回黑色。

    function TestBadColor() {
    $this->assertIsA($o =& CrayonBox::getColor(‘Lemon’), ‘Color’);
    $this->assertErrorPattern(‘/lemon/i’);
    // got black instead
    $this->assertEqual(‘#000000’, $o->getRgb());
    }

    以下是一个可以满足测试的CrayonBox类:

    class CrayonBox {
    /**
    * Return valid colors as color name => array(red, green, blue)
    *
    * Note the array is returned from function call
    * because we want to have getColor able to be called statically
    * so we can’t have instance variables to store the array
    * @return array
    */
    function colorList() {
    return array(
    ‘black’ => array(0, 0, 0)
    ,’green’ => array(0, 128, 0)
    // the rest of the colors ...
    ,’aqua’ => array(0, 255, 255)
    );
    }
    /**
    * Factory method to return a Color
    * @param string $color_name the name of the desired color
    * @return Color
    */
    function &getColor($color_name) {
    $color_name = strtolower($color_name);
    if (array_key_exists($color_name,
    $colors = CrayonBox::colorList())) {
    $color = $colors[$color_name];
    return new Color($color[0], $color[1], $color[2]);
    }
    trigger_error(“No color ‘$color_name’ available”);
    // default to black
    return new Color;
    }

    这显然地是一个非常简单的工厂, 它确实制造了单一化的对象(使用了颜色名字,而不是RGB数值) ,它展示了在新的对象被调用之前,是如何建立一个内部对象的。

    “工厂”促进多态

    控制被送回对象的内在状态固然重要, 但是如果促进多态即返回相同的接口多种类的对象,可以使得工厂模式的功能更为强大。

    让我们再次看一下Monopoly的例子,然后执行购买游戏中的道具的行为。在游戏中,你的任务就是买道具,包括一些基本动作。更进一步说, 有三种不同的道具: Street,RailRoad和Utility。所有三个类型的道具有一些共同点: 每个道具都被一个玩家拥有; 每个都有价格;而且每个都能为它的拥有者产生租金只要其他的玩家在它上面登陆。但道具之间还是存在差异的,举例来说, 计算租金的多少就取决于道具的类型。

    下列的代码展示了一个Property的基本类:

    // PHP5
    abstract class Property {
    protected $name;
    protected $price;
    protected $game;
    function __construct($game, $name, $price) {
    $this->game = $game;
    $this->name = $name;
    $this->price = new Dollar($price);
    }
    abstract protected function calcRent();
    public function purchase($player) {
    $player->pay($this->price);
    $this->owner = $player;
    }
    public function rent($player) {
    if ($this->owner
    && $this->owner != $player
    $player($this->calcRent())
    );
    }
    }
    }

    这里, Property类和CalcRent() 方法都被声明为基类。

    注:术语 – 基类
    一个基类就是不能被直接实例化的类。 一个基础的类包含一个或更多的基础方法,这些方法必须在子类被覆盖。一旦所有的抽象方法被覆盖了, 子类也就产生了。
    基类为许多相似的类创造了好的原型。
    CalcRent() 方法必须在子类被覆盖,从而形成一个具体的类。因此, 每个子类包括:Street,RailRoad和Utility,和必须定义的calcRent() 方法。

    为实现以上的情况,这三个类可以定义为:

    class Street extends Property {
    protected $base_rent;
    public $color;
    public function setRent($rent) {
    $this->base_rent = new Dollar($rent);
    }
    protected function calcRent() {
    if ($this->game->hasMonopoly($this->owner, $this->color)) {
    return $this->base_rent->add($this->base_rent);
    }
    return $this->base_rent;
    }
    }
    class RailRoad extends Property {
    protected function calcRent() {
    switch($this->game->railRoadCount($this->owner)) {
    case 1: return new Dollar(25);
    case 2: return new Dollar(50);
    case 3: return new Dollar(100);
    case 4: return new Dollar(200);
    default: return new Dollar;
    }
    }
    }
    class Utility extends Property {
    protected function calcRent() {
    switch ($this->game->utilityCount($this->owner)) {
    case 1: return new Dollar(4*$this->game->lastRoll());
    case 2: return new Dollar(10*$this->game->lastRoll());
    default: return new Dollar;
    }
    }
    }

    每个子类都继承了Property类,而且包括它自己的protected ClacRent() 方法。随着所有的基础方法都被定义, 每个子类都被实例化了。

    为了开始游戏, 所有的Monopoly道具必须被创建起来。因为这章是介绍工厂模式的,所有Property的类型存在很多共性,你应该想到多态性,从而建立所有需要的对象。

    我们还是以道具工厂类开始。 在我住的地方,政府的Assessor(定税人)掌握了税务和契约, 因此我命名它为的道具定税工厂。下一步,这个工厂将制造全部的专有道具。在真正应用时,所有的Monopoly道具的数值可能都取自于一个数据库或者一个文本, 但是对于这一个例子来说, 可以仅仅用一个数组来代替:

    class Assessor {
    protected $prop_info = array(
    // streets
    ‘Mediterranean Ave.’ => array(‘Street’, 60, ‘Purple’, 2)
    ,’Baltic Ave.’ => array(‘Street’, 60, ‘Purple’, 2)
    //more of the streets...
    ,’Boardwalk’ => array(‘Street’, 400, ‘Blue’, 50)
    // railroads
    ,’Short Line R.R.’ => array(‘RailRoad’, 200)
    //the rest of the railroads...
    // utilities
    ,’Electric Company’ => array(‘Utility’, 150)
    ,’Water Works’ => array(‘Utility’, 150)
    );
    }

    Property子类需要实例化Monopoly道具。现在,我们只是简单的用一个函数定义实例化变量$game,那么再把它加入Assessor类好了。

    class Assessor {
    protected $game;
    public function setGame($game) { $this->game = $game; }
    protected $prop_info = array(/* ... */);
    }

    也许你会偏向于选择使用数据库记录数据,不会用数组, 因为有一大堆的参数不可避免地要被罗列。如果是这样的话,可以考虑使用" 引入叁数对象 " 进行重构。

    注:重构-引入叁数对象
    方法中如果有很多参数,常常变得很复杂,而且容易导致错误。你可以引入一个封装参数的对象来替代一大堆的参数。举例来说,“start date” and “end date” 叁数可以用一个 DateRange 对象一起代替。

    在Monopoly这个例子中,这个参数对象应该是什么呢?PropertyInfo,怎样?它的目的是使每个道具参数数组引入 PropertyInfo 类的构造器中,然后返回一个新对象。目的就意味着设计, 依照 TDD, 那意味着一个测试情形。

    下面一个测试代码就是测试 PropertyInfo 类的:

    function testPropertyInfo() {
    $list = array(‘type’,’price’,’color’,’rent’);
    $this->assertIsA(
    $testprop = new PropertyInfo($list), ‘PropertyInfo’);
    foreach($list as $prop) {
    $this->assertEqual($prop, $testprop->$prop);
    }
    }

    这个测试证明:每个PropertyInfo类都有四个公共属性,而且具有按精确次序排列的叁数。
    但是因为实例中 RailRoad 和  Utility 类并不需要颜色或者租用数据, 所以我们需要测试PropertyInfo 也能引入少量的参数而实例化为RailRoad 和  Utility 类对象:

    function testPropertyInfoMissingColorRent() {
    $list = array(‘type’,’price’);
    $this->assertIsA(
    $testprop = new PropertyInfo($list), ‘PropertyInfo’);
    $this->assertNoErrors();
    foreach($list as $prop) {
    $this->assertEqual($prop, $testprop->$prop);
    }
    $this->assertNull($testprop->color);
    $this->assertNull($testprop->rent);
    }

    注:assertNoErrors()
    assertNoErrors() 方法的作用是:证实没有PHP 错误发生。如果有错误, 将不通过测试。
    assertNull()
    assertNull()方法的作用是:测试第一个参数是否为空。 如果第一个参数不为空, 将不通过测试。像大多数其他测试方法一样,, 你可以选择是否使用第二个叁数定义失败信息。

    为了满足前面的测试,PropertyInfo 类定义为:

    class PropertyInfo {
    const TYPE_KEY = 0;
    const PRICE_KEY = 1;
    const COLOR_KEY = 2;
    const RENT_KEY = 3;
    public $type;
    public $price;
    public $color;
    public $rent;
    public function __construct($props) {
    $this->type =
    $this->propValue($props, ‘type’, self::TYPE_KEY);
    $this->price =
    $this->propValue($props, ‘price’, self::PRICE_KEY);
    $this->color =
    $this->propValue($props, ‘color’, self::COLOR_KEY);
    $this->rent =
    $this->propValue($props, ‘rent’, self::RENT_KEY);
    }
    protected function propValue($props, $prop, $key) {
    if (array_key_exists($key, $props)) {
    return $this->$prop = $props[$key];
    }
    }
    }

    现在PropertyInfo 类可以构造各种不同的Property参数了。同时Assessor类可以提供数据来建立正确的PropertyInfo对象。
    现在以Assessor->$prop_info数组提供的数据为基础,新建一个实例化 PropertyInfo 的类。
    这样的代码可以是:

    class Assessor {
    protected $game;
    public function setGame($game) { $this->game = $game; }
    public function getProperty($name) {
    $prop_info = new PropertyInfo($this->prop_info[$name]);
    switch($prop_info->type) {
    case ‘Street’:
    $prop = new Street($this->game, $name, $prop_info->price);
    $prop->color = $prop_info->color;
    $prop->setRent($prop_info->rent);
    return $prop;
    case ‘RailRoad’:
    return new RailRoad($this->game, $name, $prop_info->price);
    break;
    case ‘Utility’:
    return new Utility($this->game, $name, $prop_info->price);
    break;
    default: //should not be able to get here
    }
    }
    protected $prop_info = array(/* ... */);
    }

    这段代码实现了上述功能, 但却非常脆弱。如果代入的值是$this->prop_info数组中没有的值,结果会怎样呢?因为 PropertyInfo 已经被实例化并被加入到Assessor代码中, 没有有效的方法测试被产生的对象。比较好的解决就是:产生一个工厂方法使 PropertyInfo 对象更容易建立。 因此, 下一步将是写一个测试来实现Assessor类中的PropertyInfo方法。

    但是,有一个问题: 这个方法不应该是Assessor类的公共接口(API)的一个部份。它能被测试吗?

    这里有两个方法, 可以探究任何要求的合理数量的测试。简单的说, 你可以运行黑匣子测试或白匣子测试。

    注:黑匣子测试(Black Box Testing)
    黑匣子测试就是:把被测试的对象当成" 黑匣子 " ,我们只知道它提供的应用接口(API),但不知道其到底执行了什么。它主要测试对象公共方法的输入和输出。
    白匣子测试(White Box Testing)
    白匣子测试和黑匣子测试恰恰相反, 它假定知道测试对象中的所有代码信息。这种形式的测试是为了完善代码和减少错误。
    关于白匣子测试的详细说明请见:http:// c 2.com/cgi/wiki?WhiteBoxTesting 。

    别把话题扯远了。那么如何才在黑匣子和白匣子之间找到折中办法来实现TDD呢呢?一种选择就是使原来的类中的私有方法变为公有,并且在发布的时候变回私有。但这并不是十分令人满意的方式,所以我们建立一个子类,同时使子类中的方法可以从外部访问:

    下面就是一个子类的例子:

    class TestableAssessor extends Assessor {
    public function getPropInfo($name) {
    return Assessor::getPropInfo($name);
    }
    }

    这样做的好处是你可以得到正确的Assessor公有接口(API), 但通过 TestableAssessor 类我们就可以来测试Assessor类了。另外, 你用于测试的代码也不会影响到Assessor类。

    缺点是:外加的类会带来更多的问题,从而使测试变得更复杂。而且如果你在对象中的一些内部接口作出一些改动, 你的测试将随着你的重构而再次失效。

    比较了它的优点和缺点,让我们来看看它的测试方法:

    function testGetPropInfoReturn() {
    $assessor = new TestableAssessor;
    $this->assertIsA(
    $assessor->getPropInfo(‘Boardwalk’), ‘PropertyInfo’);
    }

    为了要保证所有代码的正确执行, 我们可以使用异常处理。 SimpleTest的目前是基于PHP4 搭建的测试的结构,所以不具备异常处理能力。但是你还是可以在测试中使用如下。

    function testBadPropNameReturnsException() {
    $assessor = new TestableAssessor;
    $exception_caught = false;
    try { $assessor->getPropInfo(‘Main Street’); }
    catch (InvalidPropertyNameException $e) {
    $exception_caught = true;
    }
    $this->assertTrue($exception_caught);

    最后, Assessor类的执行部分完成了:

    class Assessor {
    protected $game;
    public function setGame($game) { $this->game = $game; }
    public function getProperty($name) {
    $prop_info = $this->getPropInfo($name);
    switch($prop_info->type) {
    case ‘Street’:
    $prop = new Street($this->game, $name, $prop_info->price);
    $prop->color = $prop_info->color;
    $prop->setRent($prop_info->rent);
    return $prop;
    case ‘RailRoad’:
    return new RailRoad($this->game, $name, $prop_info->price);
    break;
    case ‘Utility’:
    return new Utility($this->game, $name, $prop_info->price);
    break;
    default: //should not be able to get here
    }
    }
    protected $prop_info = array(/* ... */);
    protected function getPropInfo($name) {
    if (!array_key_exists($name, $this->prop_info)) {
    throw new InvalidPropertyNameException($name);
    }
    return new PropertyInfo($this->prop_info[$name]);
    }
    }

    Assessor::getPropInfo()方法从逻辑上说明 PropertyInfo工厂类是作为了Assessor类的一个私有的方法。而Assessor::getProperty() 方法是用来返回三个Property子类的一个,至于返回哪一个子类这要看property的名字。

    迟加载(Lazy Loading)的工厂

    使用工厂的另一个好处就是它具有迟加载的能力。这种情况常被用在:一个工厂中包括很多子类,这些子类被定义在单独的PHP文件内。

    注:术语 - 迟加载
    在迟加载模式中是不预加载所有的操作(像包含PHP文件或者执行数据库查询语句),除非脚本中声明要加载。

    用一个脚本可以有效地控制多个网页的输出,这是Web常用的方法了。比如一个博客程序,一些入口就有不同的页面来实现,一个简单的评论入口就有:发布评论的页面,一个导航的页面,一个管理员编辑的页面等。 你可以把所有的功能放入一个单独的类中,使用工厂来加载他们。每一个功能类可以单独放在一个文件里,再把这些文件都放在“pages”这个子文件夹里,这样可以方便调用。

    实现迟加载的页面工厂(page factory)的代码可以写作:

    class PageFactory {
    function &getPage() {
    $page = (array_key_exists(‘page’, php教程:php设计模式介绍之工厂模式 - 凌众科技

    快速业务通道

    php教程:php设计模式介绍之工厂模式

    作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-15
    content

    凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

    分享到: 更多

    Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

    地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

    电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

    《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号

    REQUEST))
    ? strtolower( php教程:php设计模式介绍之工厂模式 - 凌众科技
    快速业务通道

    php教程:php设计模式介绍之工厂模式

    作者 佚名技术 来源 NET编程 浏览 发布时间 2012-03-15
    content

    凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

    分享到: 更多

    Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

    地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

    电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

    《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号

    REQUEST[‘page’])
    : ‘’;
    switch ($page) {
    case ‘entry’: $pageclass = ‘Detail’; break;
    case ‘edit’: $pageclass = ‘Edit’; break;
    case ‘comment’: $pageclass = ‘Comment’; break;
    default:
    $pageclass = ‘Index’;
    }
    if (!class_exists($pageclass)) {
    require_once ‘pages/’.$pageclass.’.php’;
    }
    return new $pageclass;
    }
    }

    你可以利用 PHP 的动态加载性质,然后使用实时的运行需求(run-time)来给你要建立的类命名。在这情况下, 根据一个 HTTP 请求叁数就能确定哪个页面被加载。你可以使用迟加载,这样只要当你需要建立新对象时才载入相应的类,不需要你载入所有可能用到的“page”类。在上述例子中就用了 require_once来实现这一点。这个技术对于一个装有PHP加速器的系统来说并不重要,因为包含一个外加的文件使用的时间对它来说可以忽略。 但对于大多数典型的PHP服务器来说,这样做是很有好处的。

    要想了解更多的关于迟加载的知识,请看第 11 章-代理模式。

    小节

    工厂模式是非常简单而且非常有用。如果你已经有很多关于工厂模式的例子代码,你会发现更多的东西。《GoF》这本书就介绍了一些关于构建的模式:AbstractFactory and Builder。  AbstractFactory用来处理一些相关组件,Builder模式则是使建立复杂对象更为容易。

    在这章的多数例子里, 参数是通过工厂方法引入的(例如 CrayonBox::getColor(‘红色’);)。《GoF》中则称为“参数化工厂”(parameterized factory),它是PHP网页设计中典型的工厂方法。

    你现在已经了解工厂模式了, 它是一种代码中建立新对象的管理技术。 你可以看到工厂模式是可以把复杂对象的建立集中起来,甚至用不同的类代替不同的对象。最后,工厂模式支持OOP技术中的多态也是很重要的。

    凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

    分享到: 更多

    Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

    地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

    电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

    《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号