访问者模式

✍ dations ◷ 2025-10-25 07:26:14 #访问者模式

访问者模式是一种将算法与对象结构分离的软件设计模式。

这个模式的基本想法如下:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个accept方法用来接受访问者对象;访问者是一个接口,它拥有一个visit方法,这个方法对访问到的对象结构中不同类型的元素作出不同的反应;在对象结构的一次访问过程中,我们遍历整个对象结构,对每一个元素都实施accept方法,在每一个元素的accept方法中回调访问者的visit方法,从而使访问者得以处理对象结构的每一个元素。我们可以针对对象结构设计不同的实在的访问者类来完成不同的操作。

访问者模式使得我们可以在传统的单分派语言(如Smalltalk、Java和C++)中模拟双分派技术。对于支持多分派的语言(如CLOS),访问者模式已经内置于语言特性之中了,从而不再重要。

"""Visitor pattern example."""from abc import ABCMeta, abstractmethodNOT_IMPLEMENTED = "You should implement this."class CarElement:    __metaclass__ = ABCMeta    @abstractmethod    def accept(self, visitor):        raise NotImplementedError(NOT_IMPLEMENTED)class Body(CarElement):    def accept(self, visitor):        visitor.visitBody(self)class Engine(CarElement):    def accept(self, visitor):        visitor.visitEngine(self)class Wheel(CarElement):    def __init__(self, name):        self.name = name    def accept(self, visitor):        visitor.visitWheel(self)class Car(CarElement):    def __init__(self):        self.elements =     def accept(self, visitor):        for element in self.elements:            element.accept(visitor)        visitor.visitCar(self)class CarElementVisitor:    __metaclass__ = ABCMeta    @abstractmethod    def visitBody(self, element):        raise NotImplementedError(NOT_IMPLEMENTED)    @abstractmethod    def visitEngine(self, element):        raise NotImplementedError(NOT_IMPLEMENTED)    @abstractmethod    def visitWheel(self, element):        raise NotImplementedError(NOT_IMPLEMENTED)    @abstractmethod    def visitCar(self, element):        raise NotImplementedError(NOT_IMPLEMENTED)class CarElementDoVisitor(CarElementVisitor):    def visitBody(self, body):        print("Moving my body.")    def visitCar(self, car):        print("Starting my car.")    def visitWheel(self, wheel):        print("Kicking my {} wheel.".format(wheel.name))    def visitEngine(self, engine):        print("Starting my engine.")class CarElementPrintVisitor(CarElementVisitor):    def visitBody(self, body):        print("Visiting body.")    def visitCar(self, car):        print("Visiting car.")    def visitWheel(self, wheel):        print("Visiting {} wheel.".format(wheel.name))    def visitEngine(self, engine):        print("Visiting engine.")car = Car()car.accept(CarElementPrintVisitor())car.accept(CarElementDoVisitor())

Java的例子

 interface Visitor {     void visit(Wheel wheel);     void visit(Engine engine);     void visit(Body body);     void visit(Car car); } class Wheel {     private String name;     Wheel(String name) {         this.name = name;     }     String getName() {         return this.name;     }     void accept(Visitor visitor) {         visitor.visit(this);     } }   class Engine {     void accept(Visitor visitor) {         visitor.visit(this);     } } class Body {     void accept(Visitor visitor) {         visitor.visit(this);     } } class Car {     private Engine  engine = new Engine();     private Body    body   = new Body();     private Wheel wheels          = { new Wheel("front left"), new Wheel("front right"),             new Wheel("back left") , new Wheel("back right")  };     void accept(Visitor visitor) {         visitor.visit(this);         engine.accept(visitor);         body.accept(visitor);         for (int i = 0; i < wheels.length; ++ i)             wheels.accept(visitor);     } } class PrintVisitor implements Visitor {     public void visit(Wheel wheel) {         System.out.println("Visiting " + wheel.getName()                             + " wheel");     }     public void visit(Engine engine) {         System.out.println("Visiting engine");     }     public void visit(Body body) {         System.out.println("Visiting body");     }     public void visit(Car car) {         System.out.println("Visiting car");     } } public class VisitorDemo {     static public void main(String args) {         Car car = new Car();         Visitor visitor = new PrintVisitor();         car.accept(visitor);     } }

一个实际的例子

这个例子是Htmlparser计划(页面存档备份,存于互联网档案馆)里的一段示例。为获得一个Web页面的所有内容,采用如下的方式使用类 TextExtractingVisitor:

Parser parser = new Parser("http://pageIwantToParse.com");TextExtractingVisitor visitor = new TextExtractingVisitor();parser.visitAllNodesWith(visitor);System.out.println(visitor.getExtractedText());

参考条目

  • 软件设计模式
  • 组合模式


相关

  • 澳大利亚原住民语言澳大利亚原住民语言包括在澳大利亚大陆和周边岛屿(不过一般不包括塔斯马尼亚岛)使用的语言,可以分为数个语系和一些孤立语言,其中最著名的是帕马-恩永甘语系。欧洲人来澳前,澳大
  • 施瓦本汝拉山坐标:48°18′N 9°21′E / 48.3°N 9.35°E / 48.3; 9.35施瓦本汝拉山(德语:Schwäbische Alb、Schwäbischer Jura 或 Schwabenalb;英语:Swabian Jura;法语:Jura souabe)是德国的
  • 无为金丹道无为金丹道,前身为圣贤道,是二十世纪中期活跃于中国山东省北部的一个会道门,该会道门声称“末劫年”即将到来,并吸引大量农民入教。1951年8月,该会道门在博兴县发动武装暴动,建立
  • 卷舌音卷舌音(英语:Retroflex),又称翘舌音、舌尖后音。指辅音的舌尖音中,舌尖和上颚前部接触以形成对气流的阻碍而发出来的音。国际音标中采用以下的符号来记录卷舌音,是在对应的齿龈音
  • 墨子 (书)《墨子》是中国战国著名科学家、思想家、政治家墨子的著作,共五十三篇传世于今。《汉书·艺文志》云“墨子七十一篇”,现存《墨子》五十三篇,由墨子和各代门徒逐渐增补而成,是研
  • 辛 (天干)辛,天干的第八位。其在方位上指西北偏西方(285°),五行属金,阴阳属阴。天干亦可表示植物的生长周期,辛指新一轮的种子,引申万物更新。
  • 成都市第七中学成都市第七中学,简称成都七中,是位于四川省成都市的一所高中,前身肇基于始建于宋元时期的墨池书院,近代校史开始于1905年成立的成都县立高等小学堂,后改为成都县立中学校。2014年
  • 2世纪101年1月1日至200年12月31日的这一段期间被称为2世纪。
  • 吾妻日出夫吾妻日出夫(日语:吾妻 日出夫/あづま ひでお ,1950年2月6日-2019年10月13日),日本男性漫画家,北海道十胜郡浦幌町宝町出身。他的笔名是吾妻 ひでお,日语读音与本名相同。从1972年起以美少女、荒谬科幻、搞笑、戏仿等风格著称,是80年代后日本美少女、萝莉控风潮的滥觞,影响现今日本动漫、御宅族文化甚钜。全盛期一个月要交130张原稿。庞大的工作压力让吾妻在80到90年间曾因酒瘾多次入院治疗,两度失踪成为街友,企图自杀但失败。他将这段期间的经历以诙谐手法画成漫画作品《失踪日记》(失踪日記),于20
  • 神化娇娇女《神奇糖》(日语:ふしぎなメルモ)是日本漫画家手冢治虫的作品,于《小学一年生》上进行连载。故事的主角是一位小女孩メルモ。在她九岁那年,她妈妈下班途中出车祸去世了。她妈妈死后灵魂被送到天堂,由于十分担心家中的三个小孩(他们年纪都还很小,即使是年纪最大的メルモ也才九岁;这个年纪的孩子都很难独自生活了,更何况还要照顾两名弟弟),于是央求天神让她回去照顾小孩;但碍于“人死不能复生”,天神也不能答应这个要求。最后,天神给妈妈一罐神奇糖果,让她转交给メルモ。吃下红色糖果则能瞬间变大人,吃下蓝色糖果则会变回小孩;连续吃