浅谈PHP面向对象之访问者模式+组合模式

 更新时间:2017年05月22日 09:12:55   投稿:jingxian  
下面小编就为大家带来一篇浅谈PHP面向对象之访问者模式+组合模式。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

因为原文中延续了组合模式的代码示例来讲访问者模式 所以这里就合并一起来复习了。但主要还是讲访问者模式。顾名思义这个模式会有一个访问者类,被访问者类调用访问者类的时候会将自身传递给它使用。

直接看代码:

//被访问者基类

abstract class Unit {
  abstract function bombardStrength();  //获取单位的攻击力
  

  //这个方法将调用访问者类,并将自身传递给它
  function accept(ArmyVisitor $visitor){
    $method = "visit" . get_class($this);
    $visitor->$method($this);      //调用访问者类的方法,这里使用了 "visit" . get_class($this) 组成了方法的名称
  }
  

  //按原文的说法是设置一个深度,虽然之后会有调用但这个方法对于理解这个模式不重要可以不用管他(原文示例代码中经常有些跟理解模式原理没太多关系的代码)
  protected function setDepth($depth){
    $this->depth = $depth;
  }

  function getDepth(){
    return $this->depth;
  }
}

 

class Archer extends Unit{
  function bombardStrength(){
    return 4;
  }
}


class LaserCannonUnit extends Unit{
  function bombardStrength(){
    return 44;
  }
}

class Cavalry extends Unit{
  function bombardStrength(){
    return 2;         

  }
}

 

//用于组合继承了unit类的实例,并让Army和TroopCarrier类继承removeUnit和addUnit方法,不放基类是因为上述的三个类已经是最小单位了不是一个军事集团removeUnit和addUnit方法对他们没用。

abstract class CompositeUnit extends Unit{
  private $units = array();    //存放任何继承了unit 类的实例

  function getComposite(){   //这个方法主要用于判断当前实例是否是一个 CompositeUnit 类
    return $this;
  }

  protected function units(){
    return $this->units;
  }

  function removeUnit(Unit $unit){    
    $this->units = array_udiff(
      $this->units,array($unit),

      function($a,$b){return ($a === $b)?0:1;}

    );  
  }

  function addUnit(Unit $unit){        
    if(in_array($unit,$this->units,true)){
      return;
    }
    $unit->setDepth($this->depth + 1);  
    $this->units[] = $unit;
  }

  function bombardStrength(){
    $ret = 0;
    foreach($this->units as $unit){
      $ret +=$unit->bombardStrength();
    }
    return $ret;
  }

  function accept(Armyvisitor $visitor){    //调用访问者
    parent::accept($visitor);       
    foreach($this->units as $thisunit){  
      $thisunit->accept($visitor);
    }
  }	
}

 



class Army extends CompositeUnit {

}



class TroopCarrier extends CompositeUnit {

}

 

//访问者类

abstract class ArmyVisitor{
  abstract function visit(Unit $node);  //访问者要执行的业务逻辑
  function visitArcher(Archer $node){  //其实我觉得对于理解来说这个抽象类有一个抽象方法visit()就够了,原文还多出下面这些方法来绕个圈调用visit

    //...... 
    $this->visit($node);
  }

  function visitCavalry(Cavalry $node){

    //.......
    $this->visit($node);
  }

  function visitLaserCannonUnit(LaserCannonUnit $node){

    //......
    $this->visit($node);
  }

  function visitTroopCarrierUnit(Cavalry $node){

    //......
    $this->visit($node);
  }

  function visitArmy(Cavalry $node){

    //......
    $this->visit($node);
  }
}

//这个访问者类主要用于获取并保存被访问者对象的信息
class TextDumpArmyVisitor extends ArmyVisitor {
  private $text = "";
  function visit(Unit $node){
    $ret = "";
    $pad = 4 * $node->getDpth();
    $ret .= sprintf("%{$pad}s","");
    $ret .=get_class($node).": ";
    $ret .= "bombard: " . $node->bombardStrength() . "\n";
    $this->text .=$ret;
  }

  function getText(){
    return $this->text;
  }
}

class TaxCollectionVisitor extends ArmyVisitor{
  private $due=0;
  private $report ="";

  function visit(Unit $node){
    $this->levy($node,1);
  }

  function visitArcher(Archer $node){    //复写了父类的方法,对于不同的单位征收不同的税
    $this->levy($node,2);
  }

  function visitCavalry(Cavalry $node){
    $this->levy($node,3);
  }

  function visitTroopCarrierUnit(TroopCarrierUnit $node){
    $this->levy($node,5);
  }

  private function levy(Unit $unit,$amount){        //主要的业务逻辑
    $this->report .= "Tax levied for" . get_class($unit);
    $this->report .= ": $amount\n";
    $this->due +=$amount;
  }

  function getReport(){
    return $this->report;
  }

  function getTax(){
    return $this->due;
  }
}


//客户端代码1(获取并输出每个对象的一些信息)
class UnitScript {
  static function joinExisting(Unit $newUnit,Unit $occupyingUnit){
    $comp;
    if(!is_null($com = $occupyingUnit->getComposite())){
      $comp->addUnit($newUnit);
    } else {
      $comp = new Army();
      $comp->addUnit($occupyingUnit);
      $com->addUnit($newUnit);
    }
    return $comp;
  }
}

 

$main_army = new Army();
UnitScript::joinExisting(new Archer(),$main_army);
UnitScript::joinExisting(new LaserCannonUnit(),$main_army);
UnitScript::joinExisting(new Cavalry(),$main_army);

$textdump = new TextDumpArmyVisitor();
$main_army->accept($textdump);
print $textdump->getText();

 

$main_army = new Army();
UnitScript::joinExisting(new Archer(),$main_army);
UnitScript::joinExisting(new LaserCannonUnit(),$main_army);
UnitScript::joinExisting(new Cavalry(),$main_army);
$taxcollector = new TaxCollectionVisitor();
$main_army->accept($taxcollector);
print $taxcollector->getTax();

    //上述的代码因为太懒没测试,抱歉! 感兴趣的朋友就自己运行调试一下吧!

以上这篇浅谈PHP面向对象之访问者模式+组合模式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Yii框架响应组件用法实例分析

    Yii框架响应组件用法实例分析

    这篇文章主要介绍了Yii框架响应组件用法,结合实例形式分析了Yii响应组件的原理及常见使用技巧,需要的朋友可以参考下
    2019-09-09
  • php实现微信支付之现金红包

    php实现微信支付之现金红包

    这篇文章主要为大家详细介绍了php实现微信支付之现金红包,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • Yii CDBCriteria常用方法实例小结

    Yii CDBCriteria常用方法实例小结

    这篇文章主要介绍了Yii CDBCriteria常用方法,结合实例形式总结分析了CDBCriteria类的功能与常用方法,具有一定参考借鉴价值,需要的朋友可以参考下
    2017-01-01
  • thinkPHP显示不出验证码的原因与解决方法分析

    thinkPHP显示不出验证码的原因与解决方法分析

    这篇文章主要介绍了thinkPHP显示不出验证码的原因与解决方法,结合具体实例形式分析了thinkPHP关于验证码显示的相关配置方法与注意事项,需要的朋友可以参考下
    2017-05-05
  • thinkPHP5.0框架事务处理操作简单示例

    thinkPHP5.0框架事务处理操作简单示例

    这篇文章主要介绍了thinkPHP5.0框架事务处理操作,结合实例形式分析了thinkPHP5针对删除操作的事务处理相关操作技巧,需要的朋友可以参考下
    2018-09-09
  • php项目接入xxl-job调度系统的示例详解

    php项目接入xxl-job调度系统的示例详解

    这篇文章主要介绍了php项目接入xxl-job调度系统的示例代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-12-12
  • PHP使用openssl扩展实现加解密方法示例

    PHP使用openssl扩展实现加解密方法示例

    这篇文章主要介绍了PHP使用openssl扩展实现加解密方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • php传值方式和ajax的验证功能

    php传值方式和ajax的验证功能

    这篇文章给大家介绍了php前台传值到后台进行验证的三种方式,以及ajax的验证功能,需要的朋友一起学习吧
    2017-03-03
  • PHP使用Session遇到的一个Permission denied Notice解决办法

    PHP使用Session遇到的一个Permission denied Notice解决办法

    这篇文章主要介绍了PHP使用Session遇到的一个Permission denied Notice解决办法,本文系统环境是ubuntu、Debian系统,有很小的概率会遇到这个提示,需要的朋友可以参考下
    2014-07-07
  • thinkPHP5框架实现基于ajax的分页功能示例

    thinkPHP5框架实现基于ajax的分页功能示例

    这篇文章主要介绍了thinkPHP5框架实现基于ajax的分页功能,结合实例形式分析了thinkPHP5框架上进行ajax分页操作的具体步骤、实现代码与相关操作方法,需要的朋友可以参考下
    2018-06-06

最新评论