PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

PHP设计模式介绍 第三章 工厂模式

PHP设计模式介绍 第三章 工厂模式

来源:互联网  作者:  发布时间:2010-05-20
在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实

别把话题扯远了。那么如何才在黑匣子和白匣子之间找到折中办法来实现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’, $_REQUEST))
? strtolower($_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技术中的多态也是很重要的。

 

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

 


延伸阅读:
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
Tags: php   设计模式   工厂模式   设计   模式  
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号