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);        //调用基类的accept方法,在第一个客户端代码条用里将会保存军事集团整体的一个信息
    foreach($this->units as $thisunit){   //调用军事单位accept方法,在第一个客户端代码条用里将会保存其中每一个军事单位的信息
      $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;
  }
}

//用于向每个对象征税的访问者类,客户端代码2中将会调用
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();

//客户端代码2(对每个对象征税,最后输出总共征收了多少)
$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();

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

时间: 2024-10-29 04:46:43

PHP面向对象之访问者模式+组合模式的相关文章

结构型模式-组合模式(树形结构的处理)

目录 1. 定义 2. 结构 3. 代码实现 4. 透明组合模式与安全组合模式 4.1 透明组合模式 4.1 安全组合模式 5. 优缺点 6. 适用场景 7. 个人理解 参考 树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等. 组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点). 1. 定义 组合模式(Composite

9 结构型模式-----组合模式

模式动机(Composite Pattern):将对象组合成树形结构来表示“整体-部分”层次.操作时,使得对部分的操作与对整体的操作具有一致性. 模式结构图: 典型的Composite结构为: 模式代码: bt_组合模式.h: 1 #ifndef CP_H 2 #define CP_H 3 #include <iostream> 4 #include <vector> 5 using namespace std; 6 7 /* 8 抽象部件类 9 */ 10 class Compo

java设计模式--结构型模式--组合模式

什么是组合模式,这个有待研究,个人觉得是各类组合而形成的一种结构吧. 组合模式: 1 组合模式 2 概述 3 将对象组合成树形结构以表示"部分-整体"的层次结构."Composite使得用户对单个对象和组合对象的使用具有一致性." 4 5 6 适用性 7 1.你想表示对象的部分-整体层次结构. 8 9 2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象. 10 11 12 参与者 13 1.Component 14 为组合中的对象声明接

Composite模式 组合模式

Android的ViewGroup 和 View 的关系,即是采用组合模式 1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象.客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的.对这些类区别使用,使得程序更加复杂.递归使用

设计模式--结构型模式--组合模式

1.组合模式 拿剪发办卡的事情来分析一下吧. 首先,一张卡可以在总部,分店,加盟店使用,那么总部可以刷卡,分店也可以刷卡,加盟店也可以刷卡,这个属性结构的店面层级关系就明确啦. 那么,总店刷卡消费与分店刷卡消费是一样的道理,那么总店与分店对会员卡的使用也具有一致性. 例子 那么加盟店就相当于叶子节点,分店和总店属于分支节点. 那我们的目的是什么呢?就是当我们在总店刷卡的时候,所有的下属店面都有了你的刷卡积分信息.因此,我们需要对具有层级关系的总店,分店,加盟店进行一致的处理,在刷卡的时候不需要关

第10章 结构型模式—组合模式

1. 组合模式(Composite Pattern)的定义 (1)将对象组合成树型结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. (2)组合模式的结构和说明 ①Component:抽象的组件对象,为组合中的对象声明接口,让客户端可以通过这个接口来访问和管理整个对象结构,可以在里面为定义的功能提供缺省的实现. ②Leaf:叶子节点对象,定义和实现叶子对象的行为,不再包含其他子节点对象. ③Composite:组合对象,通常会存储子组件,定义包含子组件的那

结构型模式-组合模式

1.定义 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 2.介绍 组合模式属于结构型模式. 组合模式有时叫做部分-整体模式,主要是描述部分与整体的关系. 组合模式实际上就是个树形结构,一棵树的节点如果没有分支,就是叶子节点;如果存在分支,则是树枝节点. 我们平时遇到的最典型的组合结构就是文件和文件夹了,具体的文件就是叶子节点,而文件夹下还可以存在文件和文件夹,所以文件夹一般是树枝节点. 3.UML类图 角色说明: Component

组合模式之拼凑的美好

廊坊的风一如既往的在窗外刮着,天地间肆意地飘洒,纵情在一刹那,为何如今仅仅剩下风吹乱我的发,乱蓬蓬的,还是去超市逛逛吧,买吃的`(*∩_∩*)′,走进华联超市,热情的店员招呼着我,開始为我介绍,推荐各种各样商品,店员向我推荐了他们的会员卡,全场全部项目均八折,每逢节假日打五折,我心想那太划算了,并且他们总店,分店,加盟店都能够用,所以就办了张会员卡.今天我们的设计模式就从超市会员卡開始说起. 这个俨然就是我们设计模式中的组合模式----组合模式有时候又叫做部分-总体模式,它使我们树型结构的问题中

设计模式学习笔记——组合模式

组合模式 组合模式,将对象组合合成树形结构以表示"部分-整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 代码实现 接口声明Component /** * 接口声明 * @author xukai 2016年3月26日 下午4:58:37 * */ public abstract class Component { protected String name; public Component(String name) { this.name = name; }