cacheinterceptor第二次访问没被调用_访问者设计模式在OSG中的应用

为什么要谈谈访问者设计模式呢?因为OSG整个引擎就是用访问者设计模式建立起来的,不论是遍历节点图,还是做各种实用的功能,都需要大量的用到访问者设计模式。

先谈谈访问者设计模式的定义。

1:什么是访问者模式

  访问者模式是一个相对比较简单,但结构又稍显复杂的模式,它讲的是表示一个作用于某对象结构中的各元素的操作,用在OSG中的话,它意味着可以派生各种该问者添加不同的功能,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。例如,你在朋友家做客,你是访问者,朋友接收你的访问,你通过朋友的描述,然后对朋友的描述做出一个判断,这就是访问者模式。

访问者模式(Visitor),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。UML结构图如下:

a33c65a051b395c222b843bd6f7eb5f8.png

  其中,Visitor是抽象访问者,为该对象结构中ConcreteElement的每一个类声明一个Visit操作;ConcreteVisitor是具体访问者,实现每个由visitor声明的操作,是每个操作实现算法的一部分,而该算法片段是对应于结构中对象的类;ObjectStructure为能枚举它的元素,可以提供一个高层的接口以允许访问者访问它的元素;Element定义了一个Accept操作,它以一个访问者为参数;ConcreteElement为具体元素,实现Accept操作。

  1. 抽象访问者

  此处可为抽象类或接口,用于声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。


public abstract class Visitor {

public abstract void visitConcreteElementA(ConcreteElementA concreteElementA);

public abstract void visitConcreteElementB(ConcreteElementB concreteElementB); }

  2. 具体访问者

  影响访问者访问到一个类后该干什么、怎么干。这里以ConcreteVisitor1为例,ConcreteVisitor2就不再赘述了。

public class ConcreteVisitor1 extends Visitor {

@Override public void visitConcreteElementA(ConcreteElementA concreteElementA) {

System.out.println(concreteElementA.getClass().getName() + " 被 " + this.getClass().getName() + " 访问");

}

@Override public void visitConcreteElementB(ConcreteElementB concreteElementB) {

System.out.println(concreteElementB.getClass().getName() + " 被 " + this.getClass().getName() + " 访问");

}

}

  3. 抽象元素

  此处为接口后抽象类,用于声明接受哪一类访问者访问,程序上是通过accpet方法中的参数来定义的。

  抽象元素有两类方法,一是本身的业务逻辑,也就是元素作为一个业务处理单元必须完成的职责;另外一个是允许哪一个访问者来访问。这里只声明的第二类即accept方法。

public abstract class Element {

public abstract void accept(Visitor visitor);

}

  4. 具体元素

  实现accept方法,通常是visitor.visit(this)。这里以ConcreteElementA为例,ConcreteElementB就不再赘述了

public class ConcreteElementA extends Element {

@Override public void accept(Visitor visitor) {

visitor.visitConcreteElementA(this); }

public void operationA() { }

}

96742843bbb83f24880c1e8903187087.png

  5. 结构对象

  元素生产者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。


public class ObjectStructure {

private List<Element> elements = new LinkedList<>();

public void attach(Element element)

{

elements.add(element);

}

public void detach(Element element) {

elements.remove(element); }

public void accept(Visitor visitor) {

for (Element element : elements) { element.accept(visitor);

} } }

  6. Client客户端

  我们通过以下场景模拟一下访问者模式


public class Client {

public static void main(String[] args) {

ObjectStructure objectStructure = new ObjectStructure(); 5objectStructure.attach(new ConcreteElementA());

objectStructure.attach(new ConcreteElementB());

ConcreteVisitor1 visitor1 = new ConcreteVisitor1();

ConcreteVisitor2 visitor2 = new ConcreteVisitor2();

objectStructure.accept(visitor1);

objectStructure.accept(visitor2); }

}

96742843bbb83f24880c1e8903187087.png

  运行结果如下:

7bd78f9dac34034cb50b3f47a1fb07b3.png

二、访问者模式的应用

  1. 何时使用

  • 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类时

  2. 方法

  • 在被访问的类里面添加一个对外提供接待访问者的接口

  3. 优点

  • 符合单一职责原则
  • 优秀的扩展性
  • 灵活性非常高

  4. 缺点

  • 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的
  • 具体元素变更比较困难
  • 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

  5. 使用场景

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖与其具体类的操作,也就是用迭代器模式已经不能胜任的情景
  • 需要对一个对结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象

  6. 目的

  • 把处理从数据结构分离出来

  7. 应用实例

  • 人类只分为男人和女人,这个性别分类是稳定的,可以在状态类中,增加“男人反应”和“女人反应”两个方法,方法个数是稳定的,不会很容易发生变化
  • 你在朋友家做客,你是访问者,朋友接受你的访问,你通过朋友的描述,然后对朋友的描述做出一个判断

  8. 注意事项

  • 访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器
  • 访问者模式适用于数据结构相对稳定的系统

三、访问者模式的实现

  下面就以上述应用实例中的人类分为男人和女人这个例子来实现访问者模式。UML图如下:

e87cfa2daa675fb6911b168cd86e3188.png

  1. Action

  抽象的状态类,主要声明以下两个方法。

  这里的关键在于人只分男人和女人,这个性别的分类是稳定的,所以可以在状态类中,增加“男人反应”和“女人反应”两个方法,方法个数是稳定的,不会容易发生变化。

96742843bbb83f24880c1e8903187087.png


1 public abstract class Action { 2 3 //得到男人的结论或反应 4 public abstract void getManConclusion(Man man); 5 6 //得到女人的结论或反应 7 public abstract void getWomanConclusion(Woman woman); 8 9 }

96742843bbb83f24880c1e8903187087.png

  2. Person

  人的抽象类。只有一个“接受”的抽象方法,它是用来获得“状态”对象的。

1 public abstract class Person { 2 3 //接受 4 public abstract void accept(Action action); 5 6 }

  3. Action类的具体实现类

  这里以成功类(Success)为例,失败类(Fail)同理。


public class Success extends Action {

@Override public void getManConclusion(Man man)

{

System.out.println("男人成功..."); }

@Override public void getWomanConclusion(Woman woman) {

System.out.println("女人成功..."); }

}

96742843bbb83f24880c1e8903187087.png

  4. Person类的具体实现类

  这里以男人类(Man)为例,女人类(Woman)同理。

  这里用到了双分派,即首先在客户程序中将具体状态作为参数传递给Man类完成了一次分派,然后Man类调用作为参数的“具体方法”中的方法getManConclusion(),同时将自己(this)作为参数传递进去,这便完成了第二次分派。accept方法就是一个双分派操作,它得到执行的操作不仅决定于Action类的具体状态,还决定于它访问的Person的类别。

96742843bbb83f24880c1e8903187087.png


1 public class Man extends Person { 2 3 @Override 4 public void accept(Action action) { 5 action.getManConclusion(this); 6 } 7 8 }

96742843bbb83f24880c1e8903187087.png

  5. 结构对象

96742843bbb83f24880c1e8903187087.png


1 public class ObjectStructure { 2 3 private List<Person> elements = new LinkedList<>(); 4 5 //增加 6 public void attach(Person person) { 7 elements.add(person); 8 } 9 10 //移除 11 public void detach(Person person) { 12 elements.remove(person); 13 } 14 15 //查看显示 16 public void display(Action action) { 17 for (Person person : elements) { 18 person.accept(action); 19 } 20 } 21 22 }

96742843bbb83f24880c1e8903187087.png

  6. Client客户端

96742843bbb83f24880c1e8903187087.png


1 public class Client { 2 3 public static void main(String[] args) { 4 ObjectStructure objectStructure = new ObjectStructure(); 5 6 objectStructure.attach(new Man()); 7 objectStructure.attach(new Woman()); 8 9 //成功 10 Success success = new Success(); 11 objectStructure.display(success); 12 13 //失败 14 Failing failing = new Failing(); 15 objectStructure.display(failing); 16 } 17 18 }

96742843bbb83f24880c1e8903187087.png

  运行结果如下:

fde92ec85c2774d382e854fee6c20bd7.png

四、双分派

  上面提到了双分派,所谓双分派是指不管类怎么变化,我们都能找到期望的方法运行。双分派意味着得到执行的操作取决于请求的种类和两个接收者的类型。

  以上述实例为例,假设我们要添加一个Marray的状态类来考察Man类和Woman类的反应,由于使用了双分派,只需增加一个Action子类即可在客户端调用来查看,不需要改动任何其他类的代码。

  而单分派语言处理一个操作是根据请求者的名称和接收到的参数决定的,在Java中有静态绑定和动态绑定之说,它的实现是依据重载和重写实现的。值得一提的是,Java是一个支持双分派的单分派语言。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/376252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows Hook(2)调用DLL函数

DLL代码 #include <Windows.h>BOOL APIENTRY DllMain( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {switch (ul_reason_for_call){case DLL_PROCESS_ATTACH:MessageBox(NULL, L"dllHook", L"Hook", MB_OK);break;case DLL_THRE…

HDU4678_Mine

很有意思&#xff0c;很好的题目。 这样的&#xff0c;一个n*m的扫雷地图&#xff0c;告诉你哪些地方是有雷的。一个人如果点在了空白处&#xff0c;那么与其相邻的&#xff08;八个方向&#xff09;的数字以及空白都会递归地显示出来&#xff0c;如果点在数字上面&#xff0c;…

pygame只能编写游戏_游戏框架搭建

游戏框架搭建目标 —— 使用 面相对象 设计 飞机大战游戏类目标明确主程序职责实现主程序类准备游戏精灵组01. 明确主程序职责回顾 快速入门案例&#xff0c;一个游戏主程序的 职责 可以分为两个部分&#xff1a;游戏初始化游戏循环根据明确的职责&#xff0c;设计 PlaneGame 类…

周末阅读:本周热门文章排行榜

那道不清说不尽的故事 iPhone 的创意并非来自乔布斯一人&#xff0c;其起源可以追溯到 Jony 的设计团队对多点触控屏幕的思考和探索&#xff0c;也正是因为对这个技术的看好&#xff0c;在对其在手机上的可行新的不断测试后&#xff0c;苹果最后下定决心进军手机领域。这篇文章…

python3 hash算法使用

python3下的pycryptodome库 from Crypto.cipher import * if __name__ __main__:message 123#MD5和SHA的用法差不多print("SHA3_512: " SHA3_512.new(message.encode(utf-8)).digest().hex())print("SHA512: " SHA512.new(message.encode(utf-8)).dig…

poj3335 半平面交

题意&#xff1a;给出一多边形。判断多边形是否存在一点&#xff0c;使得多边形边界上的所有点都能看见该点。 sol&#xff1a;在纸上随手画画就可以找出规律&#xff1a;按逆时针顺序连接所有点。然后找出这些line的半平面交。 题中给出的点已经按顺时针排好序了&#xff0c;所…

php进程间通信 yoc_续上篇Swoole多进程数据共享的问题

原因进程作为程序执行过程中资源分配的基本单位&#xff0c;拥有独立的地址空间,同一进程的线程可以共享本进程的全局变量&#xff0c;静态变量等数据和地址空间&#xff0c;但进程之间资源相互独立。由于PHP语言不支持多线程&#xff0c;因此Swoole使用多进程模式&#xff0c;…

JavaBean的规范

&#xff08;1&#xff09;JavaBean 类必须是一个公共类&#xff0c;并将其访问属性设置为 public &#xff08;2&#xff09;JavaBean 类必须有一个空的构造函数&#xff1a;类中必须有一个不带参数的公用构造器&#xff0c;此构造器也应该通过调用各个特性的设置方法来设置特…

linux虚拟机ip修改无效

把一个centos虚拟机移动到另一台电脑的时候&#xff0c;移动前是静态ip&#xff0c;移动后发现虚拟机的ip不同了。 由于使用的是NAT&#xff0c;于是就修改了虚拟机的配置&#xff0c;发现虚拟机的ip仍然不是配置文件需要的情况。 可以尝试命令nmcli con show&#xff0c;如果…

验证(Verification)与确认(Validation)的差别

验证(Verification)与确认&#xff08;Validation&#xff09;的差别 说法一&#xff1a; &#xff08;2&#xff09;“验证(Verification)”的涵义 通过提供客观证据对规定要求已得到满足的认定。 &#xff08;2&#xff09;“确认&#xff08;Validation&#xff09;”的涵义…

vscode自动格式化不符合eslint_VsCode(Visual Studio Code)格式化代码符合EsLint

利用Visual Studio Code ESlint插件&#xff0c;实现自动格式化代码步骤一&#xff1a;安装ESlint插件>点击Extensions或者CtrlShiftX>搜索ESlint>install EsLint步骤二: 重启VsCode&#xff0c; 发现代码提示报错&#xff0c;代码不符合规范步骤三&#xff1a;鼠标ho…

解读Google分布式锁服务

背景介绍 在2010年4月&#xff0c;Google的网页索引更新实现了实时更新&#xff0c;在今年的OSDI大会上&#xff0c;Google首次公布了有关这一技术的论文。 在此之前&#xff0c;Google的索引更新&#xff0c;采用的的批处理的方式(map/reduce)&#xff0c;也就是当增量数据达到…

使用PHPMailer邮件发不出去

遇到了PHPMailer发不出去邮件的问题&#xff0c;在执行smtpConnect()时失败了&#xff0c;同样的配置在其他环境就能发送邮件。 最后发现是dns没有配置&#xff0c;解析不了邮箱服务器的域名&#xff0c;所以没发出去。。。。 如果其他语言也遇到了这样的情况&#xff0c;可以…

PHPcurl抓取AJAX异步内容(转载)

PHPcurl抓取AJAX异步内容其实抓ajax异步内容的页面和抓普通的页面区别不大。ajax只不过是做了一次异步的http请求&#xff0c;只要使用firebug类似的工具&#xff0c;找到请求的后端服务url和传值的参数&#xff0c;然后对该url传递参数进行抓取即可。 利用Firebug的网络工具 …

做自适应网站专业乐云seo_自适应网站方案品牌乐云seo

自适应网站方案品牌乐云seo&#xff0c;做乐云seo网站推广哪收录比较稳定&#xff0c;下面小编从以下几点详细介绍一下自适应网站方案品牌乐云seo&#xff1a;一、乐云seo做核心关键词首页排名技术怎么样&#xff1f;孔祥永seo做核心关键词到首页的秘诀就是做好原创内容&#x…

boost windows编译

执行&#xff1a; &#xff08;1&#xff09;bootstrap.bat &#xff08;2&#xff09;b2 -j4 toolsetmsvc-9.0 linkstatic threadingmulti runtime-linkstatic address-model64 stage --stagedir“D:\Code\boost_1_66_0\lib” debug release toolset:msvc-9.0 使用vs2008编…

必应输入法产品分析

2013年4月&#xff0c;微软MSN(中国)宣布推出首款整合搜索体验的中文云输入法“必应Bing输入法”&#xff0c;其前身是“英库拼音输入法(于2012年8月发布测试版)” 在此&#xff0c;Fruits小组从宏观的软件工程角度和微观的产品实现细节对必应输入法进行了考察和分析。 &#x…

这是我第一题AC的线段树

题目简述&#xff1a; 有N个整数&#xff0c;Q次操作&#xff0c;每次操作为询问一个区间[a, b]内数的和(0号操作)或者把一个区间内的数全部加上v(1号操作) 线段树求解即可。 #include <cstdio> #include <algorithm> using std::min; using std::max; #define L(n…

a频繁连接不上redis_连接不到redis Caused by:..._慕课问答

redis装在linux虚拟机上&#xff0c;在xshell上可以成功访问redis&#xff0c;配了密码拿了老师完整的代码作测试&#xff0c;就是访问失败&#xff0c;不知道哪里出了问题地址端口密码都没错的&#xff0c;求解org.springframework.data.redis.RedisConnectionFailureExceptio…

抓localhost包 - rawcap

抓localhost包的话用wireshark好像有点麻烦&#xff0c;所以用rawcap RawCap官网 RawCap下载连接 直接运行&#xff0c;首先根据需要选择监听相应的网卡&#xff0c;然后再填写抓包文件保存的名字