Tags标签 网战地图
当前位置: 主页 > 网站建设 > PHP教程 > PHP基础 >

php设计模式介绍之伪对象模式

2011-11-16 22:42 [PHP基础] 来源于:
导读:面向对象的编程之所以丰富多彩,部分是由于对象间的相互联系与作用。一个单一的对象就能封装一 个复杂的子系统,使那些很复杂的操作能够通过一些方法的调用而简

面向对象的编程之所以丰富多彩,部分是由于对象间的相互联系与作用。一个单一的对象就能封装一 个复杂的子系统,使那些很复杂的操作能够通过一些方法的调用而简化。(无所不在的数据库连接就是 这样的一个对象实例。)

然而经常有这样的情况,对象间的交互性是如此复杂以至于我们不得 不面对类似“先有鸡还是先有蛋”这样伤脑筋的问题:如何创建并测试这样一个对象,他要 么依赖于很多已创建的对象,要么依赖于其他一些难以意识到的情况,如整个数据库的创建和测试。

问题

如何分隔并测试一个与其他对象和资源有关的代码段?又如何再创建一个或多个对 象、程序来验证你的代码能正常运行?

解决方案

当用situ(或在一个仿真的程序环境 中)测试一个对象代价不菲或困难重重时,就可用伪对象来模拟这个行为。伪对象有同真实对象一样的 接口,但却能提供预编译响应,能跟踪方法调用,并验证调用次序。

伪对象是测试的“特 别力量”。他们被秘密训练,渗透进目标代码,模拟并监视通信方式,回报结果。伪对象有助于查 找和消除程序漏洞并能支持更多正常调试环境下的“防危险”操作。

注:The ServerStub

伪对象模式是另一种测试模式ServerStub的扩展。ServerStub模式替代一个资源并返 回其方法所调用的相应值。当其参与指定次序的方法的调用时ServerStub就成了伪对象。

其并非 是一个设计模式

本章与其他章不同,因为伪对象是一个测试模式而不是设计模式。这类似于一 个附加的章节,但对它的使用确实很值得你纳入到编码进程中。另一个不同是我们不再关注这个模式如 何编码之类的基础问题,而是强调如何在SimpleTest中使用伪对象。

本章先举一个非常简单的例 子来示范SimpleTest下伪对象的基本机制。然后向你演示如何使用伪对象帮助重构已有代码与如何测试 新的解决方案。

样本代码

伪对象是对象在测试中的一个替代品,用它测试代码更加简便 。例如,替代一个真实的数据连接——这个真实的数据连接由于一些原因而不能实际连接 ——你就可以创建一个伪对象来模拟。这意味着伪对象需要准确地回应代码中所调用的相同 的应用程序接口。

让我们创建一个伪对象来替代一个简单的名为Accumulator的类,这是一个求 和的类。如下是最初的Accumulator类:

// PHP4

class Accumulator {
var $total=0;
function add($item) {
$this->total += $item;
}
function total() {
return $this->total;
}
}

这个类中add()函数先累加值 到$total变量中,再交由total()函数返回 。 一个简单的累加也可以如下面这样(下面的代码被编写为 一个函数,但它也可以写成一个类)。

function calc_total($items, &$sum) {
foreach($items as $item) {
$sum->add($item);
}
}
function calc_tax(&$amount, $rate=0.07) {
return round($amount->total() * $rate,2);
}

第一个函数calc_total()用一个累加的动作求一系列值的和。下面是简单的测试:

class MockObjectTestCase extends UnitTestCase {
function testCalcTotal() {
$sum =& new Accumulator;
calc_total(array(1,2,3), $sum);
$this- >assertEqual(6, $sum->total());
}
}

让我们关注第二个例子。假设 实现一个真实的累加动作的代价很大。那么用一个简单的对象来替代它并回应相关代码就是很好的做法 了。使用SimpleTest,你可以用如下代码创建一个伪累加动作:

为了使用伪对象,具有代表性 的做法是你亲自写一个新类(并不要求马上做)。幸运的是,SimpleTest有一种容易的手段来实现 Mock::generate() 方法。

在上面的例子中,这种手段创建了一个名为MockAccumulator的类来响 应所有Accumulator类的方法。另外,伪累加的动作还有其他手段来操作伪对象自身的实例。例如 setReturnValue()。给出一个方法名和一个值,

setReturnValue()就可以改变伪对象而给出对应 方法所调用的值。因此,这条语句$amount->setReturnValue(‘total’, 200)返回200而 不论何时调用了total()方法。

一旦进行完初始化工作后,你可以传递MockAccumulator类到 calc_tax()函数来演示一个在真实的Accumulator对象空间中的动作。

如果你止步于此 ——即用一个对象来返回所调用函数的“封装”响应——你只是使用 了ServerStub模式。 用伪对象来验证方法的调用不限于此,因为它可以不限次序与次数。

下面 是一个通过对象来验证“数据流”的例子:

class MockObjectTestCase extends UnitTestCase {
// ...
function testCalcTax() {
$amount =& new MockAccumulator($this);
$amount->setReturnValue(‘total’,200);
$amount->expectOnce(‘total’);
$this->assertEqual(
14, calc_tax($amount));
$amount->tally();
}
}

(编辑:)

本文标签:
网友评论

栏目列表

推荐文章