学习php设计模式 php实现访问者模式(Visitor)

访问者模式表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。
访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。
访问者模式多用在聚集类型多样的情况下。在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句。而访问者模式则可以比较好的解决这个问题。对每个元素统一调用$element->accept($vistor)即可。
访问者模式多用于被访问的类结构比较稳定的情况下,即不会随便添加子类。访问者模式允许被访问结构添加新的方法。
Visitor模式实际上是分离了对象结构中的元素和对这些元素进行操作的行为,从而使我们在根据对象结构中的元素进行方法调用的时候,不需要使用IF语句判断,也就是封装了操作。
但是,如果增加新的元素节点,则会导致包括访问者接口及其子类的改变,这就会违反了面向对象中的开闭原则
当这种情况出现时,一般表示访问者模式已经可能不再适用了,或者说设计时就有问题了!
一、Visitor模式结构图

二、Visitor模式中主要角色

1)抽象访问者角色(Visitor):为该对象结构(ObjectStructure)中的每一个具体元素提供一个访问操作接口。该操作接口的名字和参数标识了 要访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2)具体访问者角色(ConcreteVisitor):实现抽象访问者角色接口中针对各个具体元素角色声明的操作。
3)抽象节点(Node)角色:该接口定义一个accept操作接受具体的访问者。
4)具体节点(Node)角色:实现抽象节点角色中的accept操作。
5) 对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合(在PHP中我们使用数组代替,因为PHP中的数组本来就是一个可以放置任何类型数据的集合)
三、Visitor模式的优缺点
访问者模式有如下的优点
1)访问者模式使得增加新的操作变得很容易。使用访问者模式可以在不用修改具体元素类的情况下增加新的操作。它主要是通过元素类的accept方法来接受一个新的visitor对象来实现的。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
2)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
3)访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
4)积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。

访问者模式有如下的缺点
1)增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
2)破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。

使用Visitor模式的前提: 对象群结构中(Collection) 中的对象类型很少改变。
在接口Visitor和Element中,确保Element很少变化,也就是说,确保不能频繁的添加新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.
如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化,ConcreteVisitor也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式。

四、Visitor模式与其它模式

1、如果所浏览的结构对象是线性的,使用迭代模式而不是访问者模式也是可以的
2、访问者模式浏览合成模式的一些结构对象
以上两点来自《Java与模式》一书

五、Visitor模式PHP示例

<?php

interface Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA);
 public function visitConcreteElementB(concreteElementB $elementB);
}

interface Element {
 public function accept(Visitor $visitor);
}

/**
 * 具体的访问者1
 */
class ConcreteVisitor1 implements Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA) {
 echo $elementA->getName() . " visitd by ConcerteVisitor1 <br />";
 }

 public function visitConcreteElementB(ConcreteElementB $elementB) {
 echo $elementB->getName() . " visited by ConcerteVisitor1 <br />";
 }

}

/**
 * 具体的访问者2
 */
class ConcreteVisitor2 implements Visitor {
 public function visitConcreteElementA(ConcreteElementA $elementA) {
 echo $elementA->getName() . " visitd by ConcerteVisitor2 <br />";
 }

 public function visitConcreteElementB(ConcreteElementB $elementB) {
 echo $elementB->getName() . " visited by ConcerteVisitor2 <br />";
 }

}

/**
 * 具体元素A
 */
class ConcreteElementA implements Element {
 private $_name;

 public function __construct($name) {
 $this->_name = $name;
 }

 public function getName() {
 return $this->_name;
 }

 /**
 * 接受访问者调用它针对该元素的新方法
 * @param Visitor $visitor
 */
 public function accept(Visitor $visitor) {
 $visitor->visitConcreteElementA($this);
 }

}

/**
 * 具体元素B
 */
class ConcreteElementB implements Element {
 private $_name;

 public function __construct($name) {
 $this->_name = $name;
 }

 public function getName() {
 return $this->_name;
 }

 /**
 * 接受访问者调用它针对该元素的新方法
 * @param Visitor $visitor
 */
 public function accept(Visitor $visitor) {
 $visitor->visitConcreteElementB($this);
 }

}

/**
 * 对象结构 即元素的集合
 */
class ObjectStructure {
 private $_collection;

 public function __construct() {
 $this->_collection = array();
 }

 public function attach(Element $element) {
 return array_push($this->_collection, $element);
 }

 public function detach(Element $element) {
 $index = array_search($element, $this->_collection);
 if ($index !== FALSE) {
 unset($this->_collection[$index]);
 }

 return $index;
 }

 public function accept(Visitor $visitor) {
 foreach ($this->_collection as $element) {
 $element->accept($visitor);
 }
 }
}

class Client {

 /**
 * Main program.
 */
 public static function main() {
 $elementA = new ConcreteElementA("ElementA");
 $elementB = new ConcreteElementB("ElementB");
 $elementA2 = new ConcreteElementB("ElementA2");
 $visitor1 = new ConcreteVisitor1();
 $visitor2 = new ConcreteVisitor2();

 $os = new ObjectStructure();
 $os->attach($elementA);
 $os->attach($elementB);
 $os->attach($elementA2);
 $os->detach($elementA);
 $os->accept($visitor1);
 $os->accept($visitor2);
 }

}

Client::main();
?>

以上就是使用php实现访问者模式的代码,还有一些关于访问者模式的概念区分,希望对大家的学习有所帮助。

(0)

相关推荐

  • PHP面向对象程序设计组合模式与装饰模式详解

    本文实例讲述了PHP面向对象程序设计组合模式与装饰模式.分享给大家供大家参考,具体如下: 组合模式 定义:组合模式定义了一个单根继承体系,使具有截然不同职责的集合可以并肩工作. 一个军队的案例, <?php abstract class Unit { // 个体 abstract function bombardStrength(); } class Archer extends Unit { // 弓箭手 function bombardStrength() { return 4; } } c

  • 轻松掌握php设计模式之访问者模式

    访问者模式解决的问题 在我们的代码编写过程当中,经常需要对一些类似的对象添加一些的代码,我们以一个计算机对象打印组成部分为例来看下: /** * 抽象基类 */ abstract class Unit { /** *获取名称 */ abstract public function getName(); } /** * Cpu类 */ class Cpu extends Unit { public function getName() { return 'i am cpu'; } } /** *

  • 深入php面向对象、模式与实践

    1 语法 1.1 基础语法 clone 需要操作原对象,但又不想影响原对象. 复制代码 代码如下: $K_back = clone $K; 基本数据类型和数组都为真复制,即为真副本,当属性为对象时,为假复制,改变副本仍会影响原对象.解决方案: //在原对象中添加 function __clone(){ $this->对象 = clone $this->对象 } __clone在clone前自动触发,可以执行一些在备份前的属性操作. 2.&传递引用 方法引用传递,改变源对象 复制代码 代

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

    因为原文中延续了组合模式的代码示例来讲访问者模式 所以这里就合并一起来复习了.但主要还是讲访问者模式.顾名思义这个模式会有一个访问者类(就像近期的热播剧"人民的名义"中的检查官,跑到到贪官家里调查取证,查实后就定罪),被访问者类调用访问者类的时候会将自身传递给它使用. 直接看代码: //被访问者基类 abstract class Unit { abstract function bombardStrength(); //获取单位的攻击力 //这个方法将调用访问者类,并将自身传递给它 f

  • 学习php设计模式 php实现访问者模式(Visitor)

    访问者模式表示一个作用于某对象结构中各元素的操作.它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色. 访问者模式利用了双重分派.先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法. 访问者模式多用在聚集类型多样的情况下.在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句.而访问者模式则可以比较好的解决这个问题.对每个元素统一调用$element->accept($v

  • Python 设计模式行为型访问者模式

    目录 一.访问者模式(Visitor Pattern) 二.应用场景 三.代码示例 一.访问者模式(Visitor Pattern) 数据结构中保存着许多元素,当我们希望改变一种对元素的处理方式时,要避免重复的修改数据结构.那么就要求我们在实现代码时,将数据的处理进行分离,即:数据类只提供一个数据处理的接口,而该数据处理接口就被称之为访问者.那么,相同结构的数据面临不同的处理结果时,我们只需要创建不同的访问者. 访问者模式,指作用于一个对象结构体上的元素的操作.访问者可以使用户在不改变该结构体中

  • 快速学习C# 设计模式之职责链模式

    职责链模式简介及UML 职责链也叫责任链,他是一种行为型模式,它为请求创建了一个接收请求者对象的链,并将请求沿着这条链传递到目标对象去处理. 该模式最简单的实现方式就是运用里氏替换原则,对每个职责所持有的对象进行抽象,并使得每个职责对象都拥有共同的父类,通过对外提供出具有一般意义的接口. 范例 该范例,是我在对微服务中,服务发现的容错性进行处理的一种处理方案,考虑到服务发现过程中,如果注册中心宕机,那么可以使用本地文件存放的临时性信息,如果本地文件不存在,那么就直接用内容中存放的信息.在整个流程

  • Java设计模式之java访问者模式详解

    目录 介绍 定义及使用场景 UML类图 角色 财务案例 个人心得体会 静态分派以及动态分派 静态分派 动态分派 访问者模式中的伪动态双分派 对访问者模式的一些思考 总结 优点 缺点 适用性 参考文章 总结 介绍 访问者模式,是行为型设计模式之一 访问者模式是一种将数据操作与数据结构分离的设计模式 访问者模式的基本思想: 软件系统中拥有一个由许多对象构成的.比较稳定的对象结构,这些对象的类都拥有一个 accept 方法用来接受访问者对象的访问 访问者是一个接口,它拥有一个 visit 方法,这个方

  • 学习php设计模式 php实现合成模式(composite)

    一.意图 将对象组合成树形结构以表示"部分-整体"的层次结构.Composite使用户对单个对象和组合对象的使用具有一致性. Composite变化的是一个对象的结构和组成. 二.合成模式中主要角色 抽象组件(Component)角色:抽象角色,给参加组合的对象规定一个接口.在适当的情况下,实现所有类共有接口的缺省行为.声明一个接口用于访问和管理Component的子组件 树叶组件(Leaf)角色:在组合中表示叶节点对象,叶节点没有子节点.在组合中定义图元对象的行为. 树枝组件(Com

  • 学习JavaScript设计模式之装饰者模式

    有时我们不希望某个类天生就非常庞大,一次性包含许多职责.那么我们就可以使用装饰着模式. 装饰着模式可以动态地给某个对象添加一些额外的职责,从而不影响这个类中派生的其他对象. 装饰着模式将一个对象嵌入另一个对象之中,实际上相当于这个对象被另一个对象包装起来,形成一条包装链. 一.不改动原函数的情况下,给该函数添加些额外的功能 1. 保存原引用 window.onload = function() { console.log(1); }; var _onload = window.onload ||

  • 学习JavaScript设计模式之责任链模式

    一.定义 责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 二.示例 假设这么一个场景: 我们负责一个售卖手机的电商网站,经过分别缴纳500元定金和200元定金的两轮预定后,到了正式购买阶段.针对预定用户实行优惠,支付过500元定金的用户会收到100元的商城优惠券,支付过200元定金的用户会收到50元的商城优惠券,没有支付定金的用户归为普通购买,且在库存有限的情况下不一定保证买到. /*

  • 举例讲解设计模式中的访问者模式在Java编程中的运用

    访问者(Visitor)模式:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作.访问者模式的结构图如下: 通过上图可以看到他有如下角色: 抽象访问者(Visitor)角色:定义接口,声明一个或多个访问操作. 具体访问者(ConcreteVisitor)角色:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作. 抽象元素(Visitable)角色:声明一个接受操作,接受一个访问者对象作为一个参数. 具体元素结点(Concret

  • 学习php设计模式 php实现建造者模式

    建造者模式可以让一个产品的内部表象和和产品的生产过程分离开,从而可以生成具有不同内部表象的产品. 一.Builder模式结构图 二.Builder模式中主要角色 抽象建造者(Builder)角色:定义一个抽象接口,规范产品各个组成成分的建造(即规范具体建造者的方法实现).其中所规范的方法中必须包括建造方法和结果返回方法 具体建造者(ConcreteBuilder)角色:实现抽象建造者角色所定义的方法.具体建造者与业务逻辑关联性较大,应用程序最终会通过调用此角色中所实现的建造方法按照业务逻辑创建产

  • 学习JavaScript设计模式之中介者模式

    一.定义 面向对象设计鼓励将行为分布到各个对象中,把对象划分成更小的粒度,有助于增强对象的可复用性.但由于这些细粒度对象之间的联系激增,又可能反过来降低它们的可复用性. 中介者模式的作用就是解除对象与对象之间的紧耦合关系. 二.示例:购买商品 假设我们正在开发一个购买手机的页面,购买流程中,可以选择手机颜色以及输入购买数量,同时页面中可以对应展示输入内容.还有一个按钮动态显示下一步操作(该颜色库存量充足,显示下一步:否则显示库存不足). <div> <span>请选择颜色</

随机推荐