zoukankan      html  css  js  c++  java
  • 访问者模式

    问题:
    使用组合模式开发时,每增加一个操作,就需要在局部类和组合类的各个子类中增加对于新操作的支持,这不但会使类变得越来越臃肿,而且每次都需要对多个类的代码进行修改。

    概念:
    访问者模式,表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

    实现:

    //单个对象基类
    abstract class Unit
    {
    	protected $depth;
    
    	//判断是否为对象集合,从而决定是否支持addUnit()和removeUnit()操作
    	public function getComposite()
    	{
    		return null;
    	}
    
    	public function accept(ArmyVisitor $visitor)
    	{
    		$method = 'visit' . get_class($this);
    		$visitor->$method($this);
    	}
    
    	protected function setDepth($depth)
    	{
    		$this->depth = $depth;
    	}
    
    	public function getDepth()
    	{
    		return $this->depth;
    	}
    
    	abstract public function bombardStrength();
    }
    //对象组合基类
    abstract class CompositeUnit extends Unit
    {
    	private $units = [];
    	public function getComposite()
    	{
    		return $this;
    	}
    	protected function units()
    	{
    		return $this->units;
    	}
    	public function removeUnit(Unit $unit)
    	{
    		$this->units = array_udiff($this->units, array($unit),
    			function($a, $b) { return $a == $b ? 0 : 1; });
    	}
    	public function addUnit(Unit $unit)
    	{
    		if(in_array(($unit), $this->units, true)) {
    			return;
    		}
    		$unit->setDepth($this->depth + 1);
    		$this->units[] = $unit;
    	}
    
    	public function accept(ArmyVisitor $visitor)
    	{
    		parent::accept($visitor);
    		foreach($this->units as $unit) {
    			$unit->accept($visitor);
    		}
    	}
    }
    //单个对象具体实现
    class LaserCanon extends Unit
    {
    	public function bombardStrength()
    	{
    		return 44;
    	}
    }
    //对象组合具体实现
    class TroopCarrier extends CompositeUnit
    {
    	public function bombardStrength()
    	{
    		$ret = 0;
    		foreach($this->units() as $unit) {
    			$ret += $unit->bombardStrength();
    		}
    		return $ret;
    	}
    }
    class Army extends CompositeUnit
    {
    	public function bombardStrength()
    	{
    		$ret = 0;
    		foreach($this->units() as $unit) {
    			$ret += $unit->bombardStrength();
    		}
    		return $ret;
    	}
    }
    
    //访问者基类
    abstract class ArmyVisitor
    {
    	//默认的访问方法
    	abstract public function visit(Unit $node);
    
    	public function visitLaserCanon(LaserCanon $node)
    	{
    		$this->visit($node);
    	}
    	public function visitTroopCarrier(TroopCarrier $node)
    	{
    		$this->visit($node);
    	}
    	public function visitArmy(Army $node)
    	{
    		$this->visit($node);
    	}
    }
    //具体访问者实现
    class TextDumpArmyVisitor extends ArmyVisitor
    {
    	private $text = '';
    
    	public function visit(Unit $node)
    	{
    		$ret = '';
    		$pad = 4 * $node->getDepth();
    		$ret .= sprintf("%{$pad}s", '');
    		$ret .= get_class($node).':';
    		$ret .= 'bombard:'.$node->bombardStrength().'<br>';
    		$this->text .= $ret;
    	}
    
    	public function getText()
    	{
    		return $this->text;
    	}
    }
    
    //应用
    $army = new Army();
    $army->addUnit(new LaserCanon());
    $army->addUnit(new TroopCarrier());
    $army->addUnit(new Army());
    $textDump = new TextDumpArmyVisitor();
    $army->accept($textDump);
    echo $textDump->getText();
    

    效果:
    优点:
    1. 访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。
    2. 增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。
    3. 每增加一个操作,只需在基类中增加一个调用访问者对应方法的方法,无需对多个类进行修改,然后在观察者中实现基于多个类的多个操作方法即可。实质上就是将多个类的操作方法抽取出来放到访问者实现。
    缺点:
    外部化操作可能会破坏封装。需要在类中为访问者提供额外方法。

  • 相关阅读:
    SharePoint 2013 商务智能报表发布
    sharepoint designer web 服务器似乎没有安装microsoft sharepoint foundation
    SharePoint 2013 Designer系列之数据视图
    SharePoint 2013 Designer系列之数据视图筛选
    SharePoint 2013 Designer系列之自定义列表表单
    SharePoint 2013 入门教程之创建及修改母版页
    SharePoint 2013 入门教程之创建页面布局及页面
    SharePoint 2010 级联下拉列表 (Cascading DropDownList)
    使用SharePoint Designer定制开发专家库系统实例!
    PL/SQL Developer 建立远程连接数据库的配置 和安装包+汉化包+注册机
  • 原文地址:https://www.cnblogs.com/wujuntian/p/9658344.html
Copyright © 2011-2022 走看看