java的string访问某个元素_C#深究.net常用的23种设计模式之访问者模式(Vistor Pattern)...

一、引言

  在上一篇博文中分享了责任链模式,责任链模式主要应用在系统中的某些功能需要多个对象参与才能完成的场景。在这篇博文中,我将为大家分享我对访问者模式的理解。

二、访问者模式介绍

2.1 访问者模式的定义

   访问者模式是封装一些施加于某种数据结构之上的操作。一旦这些操作需要修改的话,接受这个操作的数据结构则可以保存不变。访问者模式适用于数据结构相对稳定的系统, 它把数据结构和作用于数据结构之上的操作之间的耦合度降低,使得操作集合可以相对自由地改变。

  数据结构的每一个节点都可以接受一个访问者的调用,此节点向访问者对象传入节点对象,而访问者对象则反过来执行节点对象的操作。这样的过程叫做“双重分派”。节点调用访问者,将它自己传入,访问者则将某算法针对此节点执行。

2.2 访问者模式的结构图

   从上面描述可知,访问者模式是用来封装某种数据结构中的方法。具体封装过程是:每个元素接受一个访问者的调用,每个元素的Accept方法接受访问者对象作为参数传入,访问者对象则反过来调用元素对象的操作。具体的访问者模式结构图如下所示。

653438f09a961d643ce4a5cc5ab7c114.png

  这里需要明确一点:访问者模式中具体访问者的数目和具体节点的数目没有任何关系。从访问者的结构图可以看出,访问者模式涉及以下几类角色。

  • 抽象访问者角色(Vistor):声明一个活多个访问操作,使得所有具体访问者必须实现的接口。

  • 具体访问者角色(ConcreteVistor):实现抽象访问者角色中所有声明的接口。

  • 抽象节点角色(Element):声明一个接受操作,接受一个访问者对象作为参数。

  • 具体节点角色(ConcreteElement):实现抽象元素所规定的接受操作。

  • 结构对象角色(ObjectStructure):节点的容器,可以包含多个不同类或接口的容器。

2.3 访问者模式的实现

   在讲诉访问者模式的实现时,我想先不用访问者模式的方式来实现某个场景。具体场景是——现在我想遍历每个元素对象,然后调用每个元素对象的Print方法来打印该元素对象的信息。如果此时不采用访问者模式的话,实现这个场景再简单不过了,具体实现代码如下所示:

aab166d6561bc2c59c6fdd1e88a29a2d.png

 1 namespace DonotUsevistorPattern 2 { 3     // 抽象元素角色 4     public abstract class Element 5     {       6         public abstract void Print(); 7     } 8  9     // 具体元素A10     public class ElementA : Element11     {    12         public override void Print()13         {14             Console.WriteLine("我是元素A");15         }16     }17 18     // 具体元素B19     public class ElementB : Element20     {21         public override void Print()22         {23             Console.WriteLine("我是元素B");24         }25     }26 27     // 对象结构28     public class ObjectStructure29     {30         private ArrayList elements = new ArrayList();31 32         public ArrayList Elements33         {34             get { return elements; }35         }36 37         public ObjectStructure()38         {39             Random ran = new Random();40             for (int i = 0; i < 6; i++)41             {42                 int ranNum = ran.Next(10);43                 if (ranNum > 5)44                 {45                     elements.Add(new ElementA());46                 }47                 else48                 {49                     elements.Add(new ElementB());50                 }51             }52         }53     }54 55     class Program56     {57         static void Main(string[] args)58         {59             ObjectStructure objectStructure = new ObjectStructure();60             // 遍历对象结构中的对象集合,访问每个元素的Print方法打印元素信息61             foreach (Element e in objectStructure.Elements)62             {63                 e.Print();64             }65 66             Console.Read();67         }68     }69 }

aab166d6561bc2c59c6fdd1e88a29a2d.png

  上面代码很准确了解决了我们刚才提出的场景,但是需求在时刻变化的,如果此时,我除了想打印元素的信息外,还想打印出元素被访问的时间,此时我们就不得不去修改每个元素的Print方法,再加入相对应的输入访问时间的输出信息。这样的设计显然不符合“开-闭”原则,即某个方法操作的改变,会使得必须去更改每个元素类。既然,这里变化的点是操作的改变,而每个元素的数据结构是不变的。所以此时就思考——能不能把操作于元素的操作和元素本身的数据结构分开呢?解开这两者的耦合度,这样如果是操作发现变化时,就不需要去更改元素本身了,但是如果是元素数据结构发现变化,例如,添加了某个字段,这样就不得不去修改元素类了。此时,我们可以使用访问者模式来解决这个问题,即把作用于具体元素的操作由访问者对象来调用。具体的实现代码如下所示:

aab166d6561bc2c59c6fdd1e88a29a2d.png

  1 namespace VistorPattern  2 {  3     // 抽象元素角色  4     public abstract class Element  5     {  6         public abstract void Accept(IVistor vistor);  7         public abstract void Print();  8     }  9  10     // 具体元素A 11     public class ElementA :Element 12     { 13         public override void Accept(IVistor vistor) 14         { 15             // 调用访问者visit方法 16             vistor.Visit(this); 17         } 18         public override void Print() 19         { 20             Console.WriteLine("我是元素A"); 21         } 22     } 23      24     // 具体元素B 25     public class ElementB :Element 26     { 27         public override void Accept(IVistor vistor) 28         { 29             vistor.Visit(this); 30         } 31         public override void Print() 32         { 33             Console.WriteLine("我是元素B"); 34         } 35     } 36  37     // 抽象访问者 38     public interface IVistor  39     { 40         void Visit(ElementA a); 41         void Visit(ElementB b); 42     } 43  44     // 具体访问者 45     public class ConcreteVistor :IVistor 46     { 47         // visit方法而是再去调用元素的Accept方法 48         public void Visit(ElementA a) 49         { 50             a.Print(); 51         } 52         public void Visit(ElementB b) 53         { 54             b.Print(); 55         } 56     } 57  58     // 对象结构 59     public class ObjectStructure 60     { 61         private ArrayList elements = new ArrayList(); 62  63         public ArrayList Elements 64         { 65             get { return elements; } 66         } 67       68         public ObjectStructure() 69         { 70             Random ran = new Random(); 71             for (int i = 0; i < 6; i++) 72             { 73                 int ranNum = ran.Next(10); 74                 if (ranNum > 5) 75                 { 76                     elements.Add(new ElementA()); 77                 } 78                 else 79                 { 80                     elements.Add(new ElementB()); 81                 } 82             } 83         } 84     } 85  86     class Program 87     { 88         static void Main(string[] args) 89         { 90             ObjectStructure objectStructure = new ObjectStructure(); 91             foreach (Element e in objectStructure.Elements) 92             { 93                 // 每个元素接受访问者访问 94                 e.Accept(new ConcreteVistor()); 95             } 96  97             Console.Read(); 98         } 99     }100 }

aab166d6561bc2c59c6fdd1e88a29a2d.png

  从上面代码可知,使用访问者模式实现上面场景后,元素Print方法的访问封装到了访问者对象中了(我觉得可以把Print方法封装到具体访问者对象中。),此时客户端与元素的Print方法就隔离开了。此时,如果需要添加打印访问时间的需求时,此时只需要再添加一个具体的访问者类即可。此时就不需要去修改元素中的Print()方法了。

三、访问者模式的应用场景

   每个设计模式都有其应当使用的情况,那让我们看看访问者模式具体应用场景。如果遇到以下场景,此时我们可以考虑使用访问者模式。

  • 如果系统有比较稳定的数据结构,而又有易于变化的算法时,此时可以考虑使用访问者模式。因为访问者模式使得算法操作的添加比较容易。

  • 如果一组类中,存在着相似的操作,为了避免出现大量重复的代码,可以考虑把重复的操作封装到访问者中。(当然也可以考虑使用抽象类了)

  • 如果一个对象存在着一些与本身对象不相干,或关系比较弱的操作时,为了避免操作污染这个对象,则可以考虑把这些操作封装到访问者对象中。

四、访问者模式的优缺点 

   访问者模式具有以下优点:

  • 访问者模式使得添加新的操作变得容易。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,添加新的操作会变得很复杂。而使用访问者模式,增加新的操作就意味着添加一个新的访问者类。因此,使得添加新的操作变得容易。

  • 访问者模式使得有关的行为操作集中到一个访问者对象中,而不是分散到一个个的元素类中。这点类似与"中介者模式"。

  • 访问者模式可以访问属于不同的等级结构的成员对象,而迭代只能访问属于同一个等级结构的成员对象。

  访问者模式也有如下的缺点:

  • 增加新的元素类变得困难。每增加一个新的元素意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中添加相应的具体操作。

五、总结

  访问者模式是用来封装一些施加于某种数据结构之上的操作。它使得可以在不改变元素本身的前提下增加作用于这些元素的新操作,访问者模式的目的是把操作从数据结构中分离出来。

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

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

相关文章

卸载 系统打印服务器,win10系统打印机驱动卸载不掉的方案介绍

win10系统使用久了&#xff0c;好多网友反馈说win10系统打印机驱动卸载不掉的问题&#xff0c;非常不方便。有什么办法可以永久解决win10系统打印机驱动卸载不掉的问题&#xff0c;面对win10系统打印机驱动卸载不掉的图文步骤非常简单&#xff0c;只需要1、开始-设备和打印机&a…

1007

package com.company;import java.util.ArrayList; import java.util.Scanner;public class Main {public static void main(String[] args) {// write your code hereScanner scnew Scanner(System.in);int Nsc.nextInt();int[] numnew int[N];//N以内的所有数int i;ArrayList…

Apache ActiveMQ中的消息级别授权

尽管上一篇文章介绍了“代理级身份验证”&#xff0c;但该博文是关于消息级更严格的授权的。 我在现实生活中的项目中并没有这么精细的授权&#xff0c;但是我想自己做&#xff0c;并为读者提供一个教程&#xff0c;以扩展他们对ActiveMQ中安全性的了解并简化他们的工作。 有…

14章总结

一.lambda表达式 1.lambda表达式简介 lambda表达式不能独立执行&#xff0c;因此必须实现函数式接口&#xff0c;并且会返回一个函数式接口的对象。 语法&#xff1a; ()->结果表达式 参数->结果表达式 (参数1&#xff0c;参数2&#xff0c;...&#xff0c;参数n)->…

一个最简单的Makefile例子(转)

原文地址&#xff1a;http://hi.baidu.com/hellosim/blog/item/42e78341b40c3e8db2b7dce3.html 转载请注明出处 1.hello.c #include <stdio.h> int main() { printf("Hello World!\n"); return 0; } 2.Makefile hello : hello.o cc -o hello h…

python基础知识资料包-Python基础知识总结——史上最全系列

一、数据类型 1、可变数据类型 a.列表(list) 列表的系列函数&#xff1a; ①append():元素的追加&#xff0c;在列表的末尾添加新的值 列表名.append(新增的值) ②insert(下标&#xff0c;值)&#xff1a;在指定下标插入指定的值 列表名.insert(下标&#xff0c;值) ③count(值…

提高速度 - MyEclipse配置

http://jingyan.baidu.com/article/f3ad7d0fddec3b09c3345ba6.html 转载于:https://www.cnblogs.com/7q4w1e/p/9706376.html

暗时间(普通的一种时间概念)

收藏18354暗时间&#xff08;普通的一种时间概念&#xff09;编辑 暗时间简单的说就是思维的时间&#xff0c;也就是没有产生直接成果的时间。一个人走路、买菜、洗脸洗手、坐公车、逛街、出游、吃饭、睡觉&#xff0c;所有这些时间都可以成为“暗时间”&#xff0c;你可以充分…

ZOJ 1586 QS Network

题目链接 QS NetworkTime Limit: 2 Seconds Memory Limit: 65536 KBSunny Cup 2003 - Preliminary Round April 20th, 12:00 - 17:00 Problem E: QS Network In the planet w-503 of galaxy cgb, there is a kind of intelligent creature named QS. QScommunicate with e…

javaone_JavaOne 2012:101种改进Java的方法-开发人员参与为何如此重要

javaoneBruno Souza &#xff0c; Martijn Verburg和Heather Vancura在希尔顿酒店的美国大陆宴会厅4中展示了“ 101种改善Java的方法&#xff1a;开发人员为何如此重要”。 他们将其分为自己最熟悉的领域。 SouJava的创始人兼协调员 Souza谈到了通过用户组的更大参与。 Verberg…

谷歌浏览器flash_谷歌浏览器不支持Flash Player的问题

更新2020.6.10&#xff0c;这个答案更新过方式1&#xff1a;老版谷歌chrome浏览器里输入&#xff1a;chrome://flags/#run-all-flash-in-allow-mode进行设定。方式2&#xff1a;新版谷歌68&#xff0c;69以上版本&#xff0c;chrome浏览器操作方式&#xff1a;新版不再允许保存…

深入理解python之self

首先明确的是self只有在类的方法中才会有&#xff0c;独立的函数或方法是不必带有self的。self在定义类的方法时是必须有的&#xff0c;虽然在调用时不必传入相应的参数。 self名称不是必须的&#xff0c;在python中self不是关键词&#xff0c;你可以定义成a或b或其它名字都可以…

Oracle12c异常关闭后启动PDBORCL(ORA-01033)

这个问题已经困扰了我好几天找解决方案&#xff0c;终于找到&#xff1a; 由于Oracle12c的特殊性&#xff0c;但许多用户并不想在创建用户时前面要加"C##" 那么就要创建PDBORCL数据库&#xff0c;来与Oracle以前的版本保持一致(如Oracle 11g) 可能由于断电或者异常关…

带有Spring Cloud Microservices的JSON Web令牌

在Keyhole&#xff0c;我们已经发布了几个有关微服务的博客 。 我们已经讨论了微服务环境中使用的架构模式&#xff0c;例如服务发现和断路器 。 我们甚至在平台和工具上发布了博客&#xff0c;例如最近关于Service Fabric的博客 。 我们已经介绍过的架构的重要组成部分是围绕…

STC用PCA测量脉宽_教你测量玉手镯圈号及如何轻松快速摘戴玉手镯?

一、如何测量玉手镯的圈号&#xff1f;测量和田玉手镯的圈号并不复杂&#xff0c;自己在家就能轻松搞定哦&#xff01;共有两种方法可选。方法一&#xff1a;游标卡尺法所需工具&#xff1a;游标卡尺具体方法&#xff1a;如照片所示&#xff0c;使用游标卡尺测量手掌最宽处(大拇…

Python中的函数(一)

接触过C语言的朋友对函数这个词肯定非常熟悉&#xff0c;无论在哪门编程语言当中&#xff0c;函数&#xff08;当然在某些语言里称作方法&#xff0c;意义是相同的&#xff09;都扮演着至关重要的角色。今天就来了解一下Python中的函数用法。 一.函数的定义 在某些编程语言当中…

Shell基础命令

它又是一种程序设计语言。作为命令语言&#xff0c;它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令&#xff1b;作为程序设计语言&#xff0c;它定义了各种变量和参数&#xff0c;并提供了许多在高级语言中才具有的控制结构&#xff0c;包括循…

电脑报警5声_电脑故障怎么判断 常见电脑故障诊断方法介绍【详解】

在电脑使用的过程&#xff0c;出现一些电脑故障是在所难免的&#xff0c;很多小伙伴对一些常见电脑故障诊断的方法不是很了解&#xff0c;不知道自己电脑出现的这些故障 究竟是什么原因造成的 。关于软件故障有很多种可能性&#xff0c;一般都是比较容易解决的&#xff0c;今天…

洛谷P3857 [TJOI2008]彩灯(线性基)

传送门 线性基裸题 直接把所有的状态都带进去建一个线性基 然后答案就是$2^{cnt}$&#xff08;$cnt$代表线性基里数的个数&#xff09; 1 //minamoto2 #include<cstdio>3 #include<cstring>4 #define ll long long5 const int N55;6 ll b[N],a[N];int n,m,cnt;char…

sort函数

sort函数:#include <algorithm>,默认从小到大&#xff0c;如果降序可写第三方函数进行排序&#xff0c;EXP:sort(array,arrayn,cmp) 1.普通排序,升序 01#include <iostream> 02#include <algorithm> 03using namespace std; 04int main() 05{ 06 int a[10]{…