PHP设计模式之访问者模式
访问者,就像我们去别人家访问,或者别人来我们家看望我们一样。我们每个人都像是一个实体,而来访的人都会一一的和我们打招呼。毕竟,我们中华民族是非常讲究礼数和好客的民族。访问者是GoF23个设计模式中最复杂的一个模式,也是各类设计模式教材都放在最后的一个模式。先不管难度如何,我们先看看它的定义和实现。
Gof类图及解释
GoF定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
GoF类图
代码实现
interface Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a);
function VisitConcreteElementB(ConcreteElementB $b);
}
class ConcreteVisitor1 implements Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a)
{
echo get_class($a) . "被" . get_class($this) . "访问", PHP_EOL;
}
public function VisitConcreteElementB(ConcreteElementB $b)
{
echo get_class($b) . "被" . get_class($this) . "访问", PHP_EOL;
}
}
class ConcreteVisitor2 implements Visitor
{
public function VisitConcreteElementA(ConcreteElementA $a)
{
echo get_class($a) . "被" . get_class($this) . "访问", PHP_EOL;
}
public function VisitConcreteElementB(ConcreteElementB $b)
{
echo get_class($b) . "被" . get_class($this) . "访问", PHP_EOL;
}
}
抽象的访问者接口及两个具体实现。可以看作是一家小两口来我们家作客咯!
interface Element
{
public function Accept(Visitor $v);
}
class ConcreteElementA implements Element
{
public function Accept(Visitor $v)
{
$v->VisitConcreteElementA($this);
}
public function OperationA()
{
}
}
class ConcreteElementB implements Element
{
public function Accept(Visitor $v)
{
$v->VisitConcreteElementB($this);
}
public function OperationB()
{
}
}
元素抽象及实现,也可以看作是要访问的实体。当然就是我和我媳妇啦。
class ObjectStructure
{
private $elements = [];
public function Attach(Element $element)
{
$this->elements[] = $element;
}
public function Detach(Element $element)
{
$position = 0;
foreach ($this->elements as $e) {
if ($e == $element) {
unset($this->elements[$position]);
break;
}
$position++;
}
}
public function Accept(Visitor $visitor)
{
foreach ($this->elements as $e) {
$e->Accept($visitor);
}
}
}
这是一个对象结构,用于保存元素实体并进行访问调用。大家在客厅里见面,互相寒暄嘛,这里就是个客厅
$o = new ObjectStructure();
$o->Attach(new ConcreteElementA());
$o->Attach(new ConcreteElementB());
$v1 = new ConcreteVisitor1();
$v2 = new ConcreteVisitor2();
$o->Accept($v1);
$o->Accept($v2);
客户端的调用,总算让大家正式见面了,互相介绍握手。一次访问就愉快的完成了。
- 让访问者调用指定的元素。这里需要注意的,访问者调用元素的行为一般是固定的,很少会改变的。也就是VisitConcreteElementA()、VisitConcreteElementB()这两个方法。也就是定义对象结构的类很少改变,但经常需要在此结构上定义新的操作时,会使用访问者模式
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类时,适用于访问者模式
- 访问者模式适合数据结构不变化的情况。所以,它是一种平常你用不上,但一旦需要的时候就只能用这种模式的模式。GoF:“大多时候你并不需要访问者模式,但当一旦你需要访问者模式时,那就是真的需要它了”。因为很少有数据结构不发生变化的情况
- 访问者模式的一些优缺点:易于增加新的操作;集中相关的操作而分离无关的操作;增加新的ConcreteElement类很困难;通过类层次进行访问;累积状态;破坏封装
我们公司的账务,只有收入和支出两项(Element),但是不同的部门(Visitor)访问的时候会给出不同的内容。比如我查看的时候只需要查看每月或每季度的汇总数据即可,财务总监则需要详细的收支记录,而会计在做账时更是需要完整的明细。可见,公司的运营还真的是需要非常广泛的知识的,不仅是管理能力,账务知识也是必要了解的内容!!
完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor.php
实例
最后一个模式的例子还是回到我们的信息发送上来。同样的还是多个服务商,它们作为访问者需要去使用各自的短信发送及APP推送接口。这时,就可以使用访问者模式来进行操作,实现这些访问者的全部操作。
访问者模式信息发送
完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/23.visitor/source/visitor-msg.php
<?php
interface ServiceVisitor
{
public function SendMsg(SendMessage $s);
function PushMsg(PushMessage $p);
}
class AliYun implements ServiceVisitor
{
public function SendMsg(SendMessage $s)
{
echo '阿里云发送短信!', PHP_EOL;
}
public function PushMsg(PushMessage $p)
{
echo '阿里云推送信息!', PHP_EOL;
}
}
class JiGuang implements ServiceVisitor
{
public function SendMsg(SendMessage $s)
{
echo '极光发送短信!', PHP_EOL;
}
public function PushMsg(PushMessage $p)
{
echo '极光推送短信!', PHP_EOL;
}
}
interface Message
{
public function Msg(ServiceVisitor $v);
}
class PushMessage implements Message
{
public function Msg(ServiceVisitor $v)
{
echo '推送脚本启动:';
$v->PushMsg($this);
}
}
class SendMessage implements Message
{
public function Msg(ServiceVisitor $v)
{
echo '短信脚本启动:';
$v->SendMsg($this);
}
}
class ObjectStructure
{
private $elements = [];
public function Attach(Message $element)
{
$this->elements[] = $element;
}
public function Detach(Message $element)
{
$position = 0;
foreach ($this->elements as $e) {
if ($e == $element) {
unset($this->elements[$position]);
break;
}
$position++;
}
}
public function Accept(ServiceVisitor $visitor)
{
foreach ($this->elements as $e) {
$e->Msg($visitor);
}
}
}
$o = new ObjectStructure();
$o->Attach(new PushMessage());
$o->Attach(new SendMessage());
$v1 = new AliYun();
$v2 = new JiGuang();
$o->Accept($v1);
$o->Accept($v2);
说明
- 我们假定发送短信和发送推送是不变的两个行为,也就是它们俩的数据结构是稳定不变的
- 这样我们就可以方便的增加ServiceVisitor,当增加百度云或者别的什么短信提供商时,就很方便的增加访问者就可以了
- 访问者模式比较适合数据结构稳定的结构。比如帐单只有收入支出、人的性别只有男女等
下期看点
至此,设计模式部分我们已经全部学习完了。其实还少了一个解释器模式,但这个模式确实是真的的非常少见,有兴趣的朋友可以自行去了解哈。
关注公众号:【硬核项目经理】获取最新文章
添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料
知乎、公众号、抖音、头条搜索【硬核项目经理】
B站ID:482780532
PHP设计模式之访问者模式的更多相关文章
- 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)
原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...
- 折腾Java设计模式之访问者模式
博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...
- C#设计模式总结 C#设计模式(22)——访问者模式(Vistor Pattern) C#设计模式总结 .NET Core launch.json 简介 利用Bootstrap Paginator插件和knockout.js完成分页功能 图片在线裁剪和图片上传总结 循序渐进学.Net Core Web Api开发系列【2】:利用Swagger调试WebApi
C#设计模式总结 一. 设计原则 使用设计模式的根本原因是适应变化,提高代码复用率,使软件更具有可维护性和可扩展性.并且,在进行设计的时候,也需要遵循以下几个原则:单一职责原则.开放封闭原则.里氏代替 ...
- 北风设计模式课程---访问者模式(Visitor)
北风设计模式课程---访问者模式(Visitor) 一.总结 一句话总结: 设计模式是日常问题的经验总结方案,所以学好设计模式对日常出现的问题可以有很好的解决. 访问者设计模式有点神似 抽象工厂模式, ...
- JAVA设计模式之访问者模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述访问者(Visitor)模式的: 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要 ...
- C#设计模式(22)——访问者模式(Vistor Pattern)
一.引言 在上一篇博文中分享了责任链模式,责任链模式主要应用在系统中的某些功能需要多个对象参与才能完成的场景.在这篇博文中,我将为大家分享我对访问者模式的理解. 二.访问者模式介绍 2.1 访问者模式 ...
- JS常用的设计模式(8)——访问者模式
GOF官方定义: 访问者模式是表示一个作用于某个对象结构中的各元素的操作.它使可以在不改变各元素的类的前提下定义作用于这些元素的新操作.我们在使用一些操作对不同的 对象进行处理时,往往会根据不同的对象 ...
- [设计模式] 23 访问者模式 visitor Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...
- 再起航,我的学习笔记之JavaScript设计模式22(访问者模式)
访问者模式 概念介绍 访问者模式(Visitor): 针对于对象结构中的元素,定义在不改变该对象的前提下访问结构中元素的新方法 解决低版本IE兼容性 我们来看下面这段代码,这段代码,我们封装了一个绑定 ...
- Head First设计模式之访问者模式
一.定义 定义:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作. 访问者模式适用于数据结构相对稳定的系统, 它把数据结构和作用于数据结构之上的操 ...
随机推荐
- 【笔记】特征脸(PCA在人脸识别领域的应用)
人脸识别与特征脸(简单介绍) 什么是特征脸 特征脸(Eigenface)是指用于机器视觉领域中的人脸识别问题的一组特征向量,该方法被认为是第一种有效的人脸识别方法. PCA的具体实现思想见 [笔记]主 ...
- JVM-初见
目录 JVM的体系结构 类加载器 双亲委派机制 Native PC程序计数器 方法区(Method Area) 栈 堆 调优工具 常见JVM调优参数 常见垃圾回收算法 引用计数算法 复制算法 标记-清 ...
- 提取网页的markdown表格利器
在线Markdown表格转换器 markdown表格转换器,蛮好用的.偶然发现的开源工具,推荐一波. 这是目标链接:https://docs.locust.io/en/stable/configura ...
- Tag Helper 标签助手
简介 标签助手是Razor 页面中自动生成HTML语句的可重用组件.标签助手对应特定的HTML标签,ASP.NET Core 包含大量与HTML标签对应的预定义标签助手. Razor页面中的标签助手作 ...
- HDFS 09 - HDFS NameNode 的高可用机制
目录 1 - 为什么要高可用 2 - NameNode 的高可用发展史 3 - HDFS 的高可用架构 3.1 Standby 和 Active 的命名空间保持一致 3.2 同一时刻只有一个 Acti ...
- Centos7上yum安装mongodb4-2
vim /etc/yum.repos.d/mongodb-org-4.2.repo [mongodb-org-4.2] name=MongoDB Repository baseurl=https:// ...
- 2018秋招C/C++面试题总结
一.C和C++的区别是什么? C是面向过程的语言,C++是在C语言的基础上开发的一种面向对象编程语言,应用广泛.C中函数不能进行重载,C++函数可以重载C++在C的基础上增添类,C是一个结构化语言,它 ...
- .Net 生成带注释的Nuget包
使用.NET Core时,我们的类库都要打包成nuget包上传到nuget服务器,以供自己或他人使用 .Net sdk提供了一个 .Net pack 命令可以生成nuget包.比如下面的命令 dotn ...
- 传统JIT和java9新特性AOT理解
java慢的原因 1. 除了少量基本类型用栈存储外,所有对象都使用堆存储.堆的性能低于栈. 2. 很多强制类型转换(cast)或加查,耗用内存大.java运行时对类型检测,如果类型不正确会抛出Cl ...
- [转]dd大牛的《背包九讲》
P01: 01背包问题 题目 有N件物品和一个容量为V的背包.第i件物品的费用是c[i],价值是w[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 基本思路 这是最 ...