php教程:php设计模式介绍之值对象模式(5)_PHP技巧_黑客防线网安服务器维护基地--Powered by WWW.RONGSEN.COM.CN

php教程:php设计模式介绍之值对象模式(5)

作者:黑客防线网安PHP教程基地 来源:黑客防线网安PHP教程基地 浏览次数:0

本篇关键词:模式对象教程介绍
黑客防线网安网讯:  PHP4样本代码:    和PHP5不一样的是,PHP4赋值对象资源的时候是拷贝该对象,这个语法的特点本质上和值对象设计模式要求正好吻合。    然而,PHP4不能控制的属性和方法函数在对...
  PHP4样本代码:
  
  和PHP5不一样的是PHP4赋值对象资源的时候是拷贝该对象这个语法的特点本质上和值对象设计模式要求正好吻合
  
  然而,PHP4不能控制的属性和方法函数在对象之外的可见性,所以实现一个值对象设计模式相对PHP5也有细微的差别
  
  假如你回想一下这本书序言中的“对象句柄”部分,它提出了三个“规则”,当你在PHP4中使用对象去模仿PHP5中的对象句柄时,这三个规则总是适用的:
  
  通过指针($obj=&newclass;)来创建对象。
  
  用指针(functionfunct(&$obj)param{})来传递对象。
  
  用指针(function&some_funct(){}$returned_obj=&some_funct())来获取一个对象。
  
  然后,值对象设计模式却不能使用上述三个“总是适用”的规则。只有忽视了这些规则,才能总是得到一个PHP4对象的拷贝(这相当于PHP5中的“克隆”操作,描述在http://www.php.net/manual/en/language.oop5.cloning.php)
  
  因为PHP4可以轻松地赋值一个对象—这在PHP语言中是一个固有的行为,所以实现变量的不可更改就需要通过值对象通用协定来实现。在PHP4中,如果要使用值对象,请不要通过指针来创建或获取一个对象,并且给所有需要保护以免外界修改的属性或者方法函数命名时,都在属性和方法函数的名字加上下划线(_)做前缀。按照协定,变量如果具有值对象的属性,应该使用一个下划线来标识它的私有性。
  
  下面是PHP4中的Dollar类:
  
  下面这个实例可以说明,你不能在PHP4中限制一个属性只能被外部更改:
  
  functionTestChangeAmount(){
  
  $d=newDollar(5);
  
  $this->assertEqual(5,$d->getAmount());
  
  //onlypossibleinphp4bynotrespectingthe_privateconvention
  
  $d->_amount=10;
  
  $this->assertEqual(10,$d->getAmount());
  
  }
  
  再重复一次,在所有PHP4对象中,私有变量的前缀使用一个下划线,但是你还是可以从外部来直接访问私有属性和方法函数。
  
  值对象中的商业逻辑
  
  值对象(ValueObjects)不仅仅用于最小限度的访问方法这样的简单的数据结构,它同样还可以包括有价值的商业逻辑。考虑以下你如果实现许多人中平均分配金钱。
  
  如果总钱数确实是可以分成整数,你可以生成一组Dollar对象,而且每一个Dollar对象都拥有相同的部分。但是当总数可以整数的美元或者美分的时候,我们该怎么处理呢?
  
  让我们开始用一个简单的代码来测试一下:
  
  //PHP5
  
  functiontestDollarDivideReturnsArrayOfDivisorSize(){
  
  $full_amount=newDollar(8);
  
  $parts=4;
  
  $this->assertIsA(
  
  $result=$full_amount->divide($parts)
  
  ,’array’);
  
  $this->assertEqual($parts,count($result));
  
  }
  
  注释assertIsA:
  
  assertIsA()的作用是让你测试:一个特定的变量是否属于一个实例化的类。当然你也可以用它来验证变量是否属于一些php类型:字符串、数字、数组等。
  
  为了实现上述测试,Dollar::divide()方法函数的编码如下…
  
  publicfunctiondivide($divisor){
  
  returnarray_fill(0,$divisor,null);
  
  }
  
  最好加上更多的细节。
  
  functiontestDollarDrivesEquallyForExactMultiple(){
  
  $test_amount=1.25;
  
  $parts=4;
  
  $dollar=newDollar($test_amount*$parts);
  
  foreach($dollar->divide($parts)as$part){
  
  $this->assertIsA($part,‘Dollar’);
  
  $this->assertEqual($test_amount,$part->getAmount());
  
  }
  
  }
  
  现在,应当返回存有正确数据的Dollar对象,而不是简单的返回数量正确的数组。
  
  实现这个仍然只需要一行语句:
  
  最后一段代码需要解决一个除数不能把Dollar的总数均匀的除开的问题。
  
  这是一个棘手的问题:如果存在不能均匀除开的情况,是第一部分还是最后一部分能得到一个额外的金额(便士)?怎样独立测试这部分的代码?
  
  一个方法是:明确指定代码最后需要实现目标:这个数组的元素数量应该是与除数表示的数量相等的,数组的元素之间的差异不能大于0.01,并且所有部分的总数应该与被除之前的总数的值是相等的。
  
  上面的描述通过正如下面的代码实现:
  
  functiontestDollarDivideImmuneToRoundingErrors(){
  
  $test_amount=7;
  
  $parts=3;
  
  $this->assertNotEqual(round($test_amount/$parts,2),
  
  $test_amount/$parts,
  
  ’Makesurewearetestinganon-trivialcase%s’);
  
  $total=newDollar($test_amount);
  
  $last_amount=false;
  
  $sum=newDollar(0);
  
  foreach($total->divide($parts)as$part){
  
  if($last_amount){
  
  $difference=abs($last_amount-$part->getAmount());
  
  $this->assertTrue($difference<=0.01);
  
  }
  
  $last_amount=$part->getAmount();
  
  $sum=$sum->add($part);
  
  }
  
  $this->assertEqual($sum->getAmount(),$test_amount);
  
  }
  
  注释assertNotEqual:
  
  当你要确保两个变量的值是不相同时,你可以用它来进行检验。这里面的值相同是PHP的”==”运算符进行判断的。任何情况下当你需要确保两个变量的值是不相同的时候,你就可以使用它。
  
  现在根据上述代码,如果来构造Dollar::divide()方法函数呢?
  
  classDollar{
  
  protected$amount;
  
  publicfunction__construct($amount=0){
  
  $this->amount=(float)$amount;
  
  }
  
  publicfunctiongetAmount(){
  
  return$this->amount;
  
  }
  
  publicfunctionadd($dollar){
  
  returnnewDollar($this->amount+$dollar->getAmount());
  
  }
  
  publicfunctiondebit($dollar){
  
  returnnewDollar($this->amount-$dollar->getAmount());
  
  }
  
  publicfunctiondivide($divisor){
  
  $ret=array();
  
  $alloc=round($this->amount/$divisor,2);
  
  $cumm_alloc=0.0;
  
  foreach(range(1,$divisor-1)as$i){
  
  $ret[]=newDollar($alloc);
  
  $cumm_alloc+=$alloc;
  
  }
  
  $ret[]=newDollar(round($this->amount-$cumm_alloc,2));
  
  return$ret;
  
  }
  
  }
  
  这段代码可以正常运行,但是仍然有一些问题,考虑一下如果在testDollarDivide()的开始处改变$test_amount为0.02;$num_parts为5;这样的临界条件,或者考虑一下当你的除数不是一个整型数字,你该怎么做?
  
  解决上边这些问题的方法是什么呢?还是使用测试导向的开发循环模式:增加一个需求实例,观察可能的错误,编写代码来生成一个新的实例进行运行,还有问题存在时继续分解。最后重复上述过程。
  
  publicfunctiondivide($divisor){
  
  returnarray_fill(0,$divisor,newDollar($this->amount/$divisor));
  
  //PHP4
  
  classDollar{
  
  var$_amount;
  
  functionDollar($amount=0){
  
  $this->_amount=(float)$amount;
  
  }
  
  functiongetAmount(){
  
  return$this->_amount;
  
  }
  
  functionadd($dollar){
  
  returnnewDollar($this->_amount+$dollar->getAmount());
  
  }
  
  functiondebit($dollar){
  
  returnnewDollar($this->_amount-$dollar->getAmount());
  
  }
  
  }
  
  
    黑客防线网安服务器维护方案本篇连接:http://www.rongsen.com.cn/show-17383-1.html
网站维护教程更新时间:2012-09-21 05:17:51  【打印此页】  【关闭
我要申请本站N点 | 黑客防线官网 |  
专业服务器维护及网站维护手工安全搭建环境,网站安全加固服务。黑客防线网安服务器维护基地招商进行中!QQ:29769479

footer  footer  footer  footer