Visitor - 访问者模式

合集下载

Visitor Pattern in Groovy

Visitor Pattern in Groovy

Visitor Pattern in GroovyGroovy是一种支持面向对象、函数式编程的动态语言。

其中一种常用的设计模式是访问者模式(Visitor Pattern)。

访问者模式是一种用于数据结构处理的设计模式,它能够将算法与数据结构分离。

访问者模式的本质是将数据结构和数据操作分离,使得操作可以独立变化。

在访问者模式中,数据结构被封装在一个访问者对象中,并且这个对象可以被多个不同的操作所共享。

当一个操作需要对数据结构进行处理时,它可以通过访问者对象来访问数据结构中的元素。

在Groovy中,我们可以通过使用闭包(Closure)来实现访问者模式。

闭包是一种能够捕获作用域内的变量,并将其保存在一个可调用对象中的特殊函数。

闭包可以用来表示一段代码块,并在后续的执行中被调用。

下面是一个使用闭包实现访问者模式的例子:```groovyclass Element {void accept(Closure closure) {closure.call(this)}}class ConcreteElement extends Element {String getName() { "ConcreteElement" }}class Visitor {void visit(Element element) {println "Visit ${}: ${element.getName()}" }}class ConcreteVisitor extends Visitor {void visit(ConcreteElement element) {println "Visit ConcreteElement: ${element.getName()}"}}def element = new ConcreteElement()def visitor = new ConcreteVisitor()element.accept(visitor.&visit)```在这个例子中,我们定义了Element和ConcreteElement两个类。

visit设计模式

visit设计模式

visit设计模式访问者模式是一种软件设计模式,它提供了一种在不需要改变各类的前提下定义新的操作方式的方法。

它属于行为模式。

一个场景是,你有一堆对象,每个对象都有一些属性和方法,但它们属于不同的类,很难再添加新的操作。

那么,你可以使用访问者模式。

在访问者模式中,有一个通用的操作,这个操作并不代表任何具体的功能,只是构成一个调用的通路。

访问者提供这个通用的操作(例如:visit),而对象提供接受这个操作的方法(例如:accept)。

在accept方法里面回调visit方法,从而回调到访问者的具体实现,而这个访问者的具体实现的方法就是要添加的新的功能。

以下是访问者模式的基本组成部分:1. 访问者(Visitor):这是一个抽象类,定义了一个或多个方法,这些方法对应于元素的某些操作。

2. 具体访问者(ConcreteVisitor):这是访问者类的一个实现,它提供了访问者类中方法的具体实现。

3. 元素(Element):这是一个接口,定义了接受访问的方法。

4. 具体元素(ConcreteElement):这是元素类的一个实现,它实现了元素接口中定义的方法。

5. 对象结构(ObjectStructure):这是包含多个元素的类。

此外,还有两次分发技术。

当客户端调用ObjectStructure的时候,会遍历ObjectStructure中所有的元素,调用这些元素的accept方法,让这些元素来接收访问,这是请求的第一次分发;在具体的元素对象中实现accept 方法的时候,会回调访问者的visit方法,等于请求被第二次分发了,请求被分发给访问者来处理,真正实现功能的正式访问者的visit方法。

此外,访问者模式一个很常见的应用就是和组合模式结合使用,通过访问者模式来给由组合模式构建的对象结构增加功能。

以上内容仅供参考,如需更多信息,建议查阅访问者模式的资料或咨询专业的编程人员。

设计模式主要分三个类型

设计模式主要分三个类型

设计模式主要分三个类型:创建型、结构型和行为型。

其中创建型有:一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。

三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。

四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。

五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。

行为型有:六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。

七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。

八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。

九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。

十、State,状态模式:允许对象在其内部状态改变时改变他的行为。

对象看起来似乎改变了他的类。

十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。

十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。

[游戏]-游戏开发中常用的设计模式

[游戏]-游戏开发中常用的设计模式

[游戏]-游戏开发中常⽤的设计模式来源:使⽤设计模式来提⾼程序库的重复利⽤性是⼤型程序项⽬开发必须的。

但是在“四⼈帮”的设计模式概述中提到了23种标准设计模式,不但难以记住,⽽且有些设计模式更多的适⽤于应⽤程序开发,对游戏项⽬引擎设计并没有很多的利⽤价值。

根据经验,精挑细选后,笃志在这⾥记录⼀些⾃认为有利⽤价值的设计模式,以便之后⾃⼰设计时使⽤。

⼀:观察者Observer观察者的设计意图和作⽤是:它将对象与对象之间创建⼀种依赖关系,当其中⼀个对象发⽣变化时,它会将这个变化通知给与其创建关系观察者的设计意图和作⽤是的对象中,实现⾃动化的通知更新。

游戏中观察者的适⽤环境有:游戏中观察者的适⽤环境有1:UI控件管理类。

当我们的GUI控件都使⽤观察者模式后,那么⽤户的任何界⾯相关操作和改变都将会通知其关联对象-----我们的UI事件机。

2:动画管理器。

很多时候我们在播放⼀个动画桢的时候,对其Frame有很⼤兴趣,此时我们设置⼀个FrameLister对象对其进⾏监视,获得我们关⼼的事件进⾏处理是必须的。

观察者伪代码::观察者伪代码// 被观察对象⽬标类Class Subject{// 对本⽬标绑定⼀个观察者 Attach( Observer );// 解除⼀个观察者的绑定 DeleteAttach( Observer );// 本⽬标发⽣改变了,通知所有的观察者,但没有传递改动了什么Notity(){For ( …遍历整个ObserverList …){ pObserver ->Update(); }}// 对观察者暴露的接⼝,让观察者可获得本类有什么变动GetState();}//-------------------------------------------------------------------------------------------------------// 观察者/监听者类Class Observer{// 暴露给对象⽬标类的函数,当监听的对象发⽣了变动,则它会调⽤本函数通知观察者Void Update (){pSubject ->GetState(); // 获取监听对象发⽣了什么变化TODO:DisposeFun(); // 根据状态不同,给予不同的处理}}⾮程序语⾔描述:⾮程序语⾔描述A是B的好朋友,对B的⾏为⾮常关⼼。

JS常用的设计模式(8)——访问者模式

JS常用的设计模式(8)——访问者模式

JS常⽤的设计模式(8)——访问者模式GOF官⽅定义:访问者模式是表⽰⼀个作⽤于某个对象结构中的各元素的操作。

它使可以在不改变各元素的类的前提下定义作⽤于这些元素的新操作。

我们在使⽤⼀些操作对不同的对象进⾏处理时,往往会根据不同的对象选择不同的处理⽅法和过程。

在实际的代码过程中,我们可以发现,如果让所有的操作分散到各个对象中,整个系统会变得难以维护和修改。

且增加新的操作通常都要重新编译所有的类。

因此,为了解决这个问题,我们可以将每⼀个类中的相关操作提取出来,包装成⼀个独⽴的对象,这个对象我们就称为访问者(Visitor)。

利⽤访问者,对访问的元素进⾏某些操作时,只需将此对象作为参数传递给当前访问者,然后,访问者会依据被访问者的具体信息,进⾏相关的操作。

据统计,上⾯这段话只有5%的⼈会看到最后⼀句。

那么通俗点讲,访问者模式先把⼀些可复⽤的⾏为抽象到⼀个函数(对象)⾥,这个函数我们就称为访问者(Visitor)。

如果另外⼀些对象要调⽤这个函数,只需要把那些对象当作参数传给这个函数,在js⾥我们经常通过call或者apply的⽅式传递 this对象给⼀个Visitor函数.访问者模式也被称为GOF总结的23种设计模式中最难理解的⼀种。

不过这有很⼤⼀部分原因是因为《设计模式》基于C++和Smalltalk写成.在强类型语⾔中需要通过多次重载来实现访问者的接⼝匹配。

⽽在js这种基于鸭⼦类型的语⾔中,访问者模式⼏乎是原⽣的实现, 所以我们可以利⽤apply和call毫不费⼒的使⽤访问者模式,这⼀⼩节更关⼼的是这种模式的思想以及在js引擎中的实现。

我们先来了解⼀下什么是鸭⼦类型,说个故事:很久以前有个皇帝喜欢听鸭⼦呱呱叫,于是他召集⼤⾂组建⼀个⼀千只鸭⼦的合唱团。

⼤⾂把全国的鸭⼦都抓来了,最后始终还差⼀只。

有天终于来了⼀只⾃告奋勇的鸡,这只鸡说它也会呱呱叫,好吧在这个故事的设定⾥,它确实会呱呱叫。

后来故事的发展很明显,这只鸡混到了鸭⼦的合唱团中。

24种设计模式及案例

24种设计模式及案例

24种设计模式及案例设计模式是软件工程中经过验证的解决其中一类常见问题的可复用设计的描述。

它们提供了一套经过验证的最佳实践,可以帮助开发人员解决各种设计问题,并提高代码的可维护性、重用性和灵活性。

本文将介绍24种常见的设计模式,并为每种模式提供一个案例,以便更好地理解和应用这些设计模式。

1.创建型模式:- 简单工厂模式(Simple Factory Pattern):通过一个工厂类根据输入参数的不同来创建不同类的对象。

- 工厂方法模式(Factory Method Pattern):定义一个创建对象的接口,但让子类决定实例化哪一个类。

- 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体的类。

- 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局的访问点来获取该实例。

2.结构型模式:- 适配器模式(Adapter Pattern):将不兼容的接口转换为可兼容的接口,以便不同类之间可以协同工作。

- 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,而不需要修改原始类的代码。

- 代理模式(Proxy Pattern):为其他对象提供一种代理以控制对该对象的访问。

- 外观模式(Facade Pattern):提供了一个简化接口,用于使用一组复杂子系统的更高级别接口。

3.行为型模式:- 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并使它们可以互相替换。

- 观察者模式(Observer Pattern):定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,其所有依赖对象都会收到通知并自动更新。

- 模板方法模式(Template Method Pattern):定义了一个操作的算法框架,而将一些步骤的实现延迟到子类中。

23种设计模式

23种设计模式

23种设计模式设计模式主要三类型:创建型、结构型⾏型其创建型:⼀、Singleton单例模式:保证类实例并提供访问全局访问点⼆、Abstract Factory抽象⼯⼚:提供创建系列相关或相互依赖象接⼝须指定具体类三、Factory Method⼯⼚:定义⽤于创建象接⼝让类决定实例化哪类Factory Method使类实例化延迟类四、Builder建造模式:复杂象构建与表⽰相离使同构建程创建同表⽰五、Prototype原型模式:⽤原型实例指定创建象种类并且通拷贝些原型创建新象⾏型:六、Iterator迭代器模式:提供顺序访问聚合象各元素需要暴露该象内部表⽰七、Observer观察者模式:定义象间依赖关系象状态发改变所依赖于象都通知⾃更新⼋、Template Method模板:定义操作算⾻架些步骤延迟类TemplateMethod使类改变算结构即重定义该算某些特定步骤九、Command命令模式:请求封装象使⽤同请求客户进⾏参数化请求排队记录请求志及⽀持撤销操作⼗、State状态模式:允许象其内部状态改变改变⾏象看起似乎改变类⼗⼀、Strategy策略模式:定义系列算封装起并使互相替换本模式使算独⽴于使⽤客户⼗⼆、China of Responsibility职责链模式:使象都机处理请求避免请求送发者接收者间耦合关系⼗三、Mediator介者模式:⽤介象封装些列象交互⼗四、Visitor访问者模式:表⽰作⽤于某象结构各元素操作使改变各元素类前提定义作⽤于元素新操作⼗五、Interpreter解释器模式:给定语⾔定义⽂表⽰并定义解释器解释器使⽤该表⽰解释语⾔句⼗六、Memento备忘录模式:破坏象前提捕获象内部状态并该象外保存状态结构型:⼗七、Composite组合模式:象组合树形结构表⽰部整体关系Composite使⽤户单象组合象使⽤具致性⼗⼋、Facade外观模式:系统组接⼝提供致界⾯fa?ade提供⾼层接⼝接⼝使系统更容易使⽤⼗九、Proxy代理模式:其象提供种代理控制象访问⼆⼗、Adapter,适配器模式:类接⼝转换客户希望另外接⼝Adapter模式使原本由于接⼝兼容能起⼯作些类起⼯作⼆⼗⼀、Decrator装饰模式:态给象增加些额外职责增加功能说Decorator模式相⽐类更加灵⼆⼗⼆、Bridge桥模式:抽象部与实现部相离使独⽴变化⼆⼗三、Flyweight享元模式。

网站的几种设计模式

网站的几种设计模式
●定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
适用性
●当一个类不知道它所必须创建的对象的类的时候。
●当一个类希望由它的子类来指定它所创建的对象的时候。
●当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
二.结构型模式
6.适配器模式 意图
●将一个类的接口ቤተ መጻሕፍቲ ባይዱ换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
适用性
●你想使用一个已经存在的类,而它的接口不符合你的需求。
●你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
●如果一个系统要将系统中所有的数据更新到日志里,以便在系统崩溃时,可以根据日志里读回所有的数据更新命令,重新调用 Execute()方法一条一条执行这些命令,从而恢复系统在崩溃前所做的数据更新。
●一个系统需要支持交易(Transaction)。一个交易结构封装了一组数据更新命令。使用命令模式来实现交易结构可以使系统增加新的交易类型。
○虚代理(Virtual Proxy )根据需要创建开销很大的对象。在动机一节描述的 ImageProxy就是这样一种代理的例子。
○保护代理(Protection Proxy )控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。例如,在Choices 操作系统[CIRM93]中 KemelProxies 为操作系统对象提供了访问保护。
适用性
●当一个抽象模型有两个方面, 其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Visitor - 访问者模式话说有一个银行,有三个窗口,但是每个窗口的智能都是一样的,即都能办理所有的业务。

因此每位来银行办理业务的人只要排队就是了,排到你了,就向业务员说明你要办理的业务,然后业务员根据你的业务选择不同的单据,打开不同的账本。

……。

业务员此时典型的工作流程是:Java代码1if (service instanceof Saving){2//存款3 ......4}else if (service instanceof Draw){5//提款6 ......7}else if (service instanceof Fund){8//基金9 ......10}11......于是每位业务员的桌面总是塞得满满的,更重要的是大量的时间都花在受理不同业务之间的切换,使得效率很低。

有没有方法能够使得业务员的工作效率提高呢?银行经理苦思冥想了半天,终于想出了一个好办法。

他让每个窗口各负责一个业务,同时委任了一位访问者(Visitor),负责在客户进门时,询问他要办理什么业务,告诉他应该去哪个窗口办理。

这样,每个窗口的业务员就只负责一项业务,减少了在不同业务间切换的时间耗费,效率大大提高。

更重要的是,当某一项业务的处理流程发生变更时,不需要同时麻烦三个窗口的业务员,而只需要让处理这项业务的业务员进行修改就可以了。

下面就来定义Visitor类,这个Visitor类实际上还办含了不同窗口受理员的职责,可以认为是银行的受理反应机制吧。

Java代码12public class Visitor {1314public void process(Service service){ 15// 默认业务16}1718public void process(Saving service){ 19// 存款20}2122public void process(Draw service){23// 提款24}2526public void process(Fund service){27// 基金28}29}接着我们定义业务基类。

Java代码30public class Service {31public void accept(Visitor visitor) {32visitor.process(this);33}34}不同的业务类。

Java代码35public class Saving extends Service {36//各种业务处理流程37}Java代码38public class Draw extends Service {39//各种业务处理流程40}Java代码41public class fund extends Service {42//各种业务处理流程43}好了,接下来就是我们的访问者与到来的客户之间的交互了。

Java代码44public class Client {45public static void main(String[] args) {46Service s1 = new Saving();47Service s2 = new Draw();48Service s3 = new Fund();4950Visitor visitor = new Visitor();5152s1.accept(visitor);53s2.accept(visitor);54s3.accept(visitor);55}56}后话:专门设定一个访问者的职位还是有点多余,于是后来银行经理请设备公司做了一个排号机来代替访问者。

总结Visitor模式实际上是利用的语言本身的特性,见Vistor类的各个函数,通过不同的参数来自动查找相应的处理函数。

采用Visitor的好处如上面说到的那样,当需要改变其中一项业务的处理时,不需要每个地方都进行修改,而只需要改动Visitor类中相应的处理函数就可以了。

也就是说它适合于业务处理时常发生变动的情况。

当然,Visitor也有它自身的限制。

它不适合于业务数量的经常变化,因为一旦新增或删除一些Service时,需要对visitor进行相应的增删。

也就是说具体Service与Visitor是耦合的。

wangdi 写道引用当然,Visitor也有它自身的限制。

它不适合于业务数量的经常变化,因为一旦新增或删除一些Service时,需要对visitor进行相应的增删。

也就是说具体Service与Visitor是耦合的。

其实,我非常想知道关于visitor模式的定义,,有了准确定义,实现应该会比较简单。

注:我这儿的accept()、process()方法和lz的对应的方法是不一样的。

Java代码1public interface IVisitor {2public void accept(IService service);3}Java代码4public interface IService {5public void process(IVisitor vistor);6}Java代码7public class Fund implements IService {8public void process(IVisitor vistor){9System.out.println("处理" + this);10}1112public String toString(){13return"基金业务";14}15}Java代码16public class Saving implements IService {17public void process(IVisitor vistor) {18System.out.println("处理" + this);19}2021public String toString() {22return"存款业务";23}24}Java代码25public class Visitor implements IVisitor {26public void accept(IService service) {27service.process(this);28}29}Java代码30public class VisitorClients0 {31public static void main(String[] args) {32IVisitor visitor = new Visitor();3334IService fundService = new Fund();35IService savingService = new Saving();3637visitor.accept(fundService);38visitor.accept(savingService);39}40}网上关于访问者大多数定义都像楼主所举的。

但是访问者模式,重点是不改变原有的类与类继承关系上,为原有的类体系增加新的功能这是类图.由于163的也是一个减化图,因此自已重新传一张,进行说明上图中ObjectStructure所指示的类结构,是固定的,是不希望发生变化的。

但是,这个类的各个子类,他们要经常增加新的功能或操作。

如何不改变这个类结构,又能在原有的基础上增加新的操作呢?则这些子类ConcreateElenmentA、ConcreateElenmentB 预先调用一个功能扩展方法(即accept).如果没有功能变化,这个对象就是null,或有他是其方法中的是一个空语句。

而这个功能扩展方法,有一个参数-------Vistor对象,这个对象装载着新功能变化。

Vistor类的方法,对应着Element中各个子类,使用了accept方法的方法,如果当Element 中的某个子类如ConcreateElenmentA,要增加功能了,则把新功能写在Vistor子类中.具体作法是,单写一个类,让它继承Vistor,由于这里是增加ConcreateElenmentA的功能,则在自已写的这个类中覆盖VistorConcreateElenmenA方法就行了。

然后把自已写的类,生成一个实例,传递给ConcreateElenmentA对象.简单说:1 Element 类继承体系中,其继承关系不变,各个子类不变。

但是,各个子类的却经常需要增加新功能。

-----------这是我们的想要达到的目的。

2 实现方法:先定义一套方法封装在vistor类中。

这套方法中,每个方法对应着一个Element子类。

Element子类则在事先在代码中,谳用这个vistor对象中与自已相对应的方法。

而accept方法,就是传输管道。

当用户要增加Element的子类ConcreateElenmentA时,具体使用如下:(1)写一个Vistor1继承Vistor。

Vistor1中,覆盖VistorConcreateElenmenA方法,写新加入的功能。

(2)生成Vistor1的实例。

其名取为vistor1(3)生成ConcreateElenmentA的实例,取名concreateElenmentA(4)定义一个Element变量,名为e,其值为vistor1 ; 定义一个Vistor变量,名为v,其值为concreateElenmentA(5)用如下语句增加ConcreateElenmentA的实例的功能。

e.accpt(v)(6)当ConcreateElenmentA的实例的功能又变化了,则修改第一条与第四条。

重写一个Vistor的子类,并赋值给变量v即可。

其他代码根本不用改变了。

出色的达到了我们想要的目的.3 这个场景可用spring的AOP4 题化话------ 访问者名字的由来。

也许是Element的各个子类---------为来访的客人预留下了座位。

来访客人每次带一大包实用的礼物,让Element的子类的实例增加自已的魔法功能。

来访的客人各不相同,带来的礼物五花八门,于是Element的子类的实例,展现出魔术般的神奇效果。

======================================================以上是三年前对vitor的个人理解。

尘封了N久的记忆,总算被打开了。

说事在的,二十三种模式,仅有少数几种留下了深刻的印像,其余的都淡忘掉了。

唯独模式设计的封装变化点在心中。

好在,还有自已能看懂的笔记一直保存着。

Visitor模式的使用情景以及与Iterator的比较见我以前的一篇文章/blog/166142这次主要讨论Visitor的两种实现方式及其优劣。

相关文档
最新文档