访问者模式

✍ dations ◷ 2025-06-19 14:02:59 #访问者模式

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

这个模式的基本想法如下:首先我们拥有一个由许多对象构成的对象结构,这些对象的类都拥有一个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());

参考条目

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


相关

  • 老年人老年(英语:old age),一般指生物的生命周期一个阶段,即中年到死亡的一段时间不同的文化圈对于老年人有着不同的定义。由于生命的周期是一个渐变的过程,壮年到老年的分界线往往是很
  • 丁苯橡胶丁苯橡胶(Styrene-Butadiene Rubber,简写:SBR)是合成橡胶的一种,由苯乙烯和丁二烯聚合而成。二战之前,德国的法本公司(I.G. Farben AG)首先开发了丁苯橡胶。主要为丁二烯和苯乙烯,
  • 约翰·拜艾兹 约翰·卡洛斯·拜艾兹(英语:John Carlos Baez,/ˈbaɪ.ɛz/,1961年6月12日-)为美国数学物理学家,任教于加州大学河滨分校数学系。其以研究循环量子引力理论中自旋泡沫著名。近
  • 巴黎十三区巴黎十三区(法语:13e arrondissement de Paris)是法国首都巴黎市的20个区之一。该区处于巴黎左岸。十三区里有巴黎的三个华人区之一。
  • 查尔斯·司布真司布真(Charles Haddon Spurgeon,1834年6月19日-1892年1月31日),19世纪英国著名浸信会牧师。他的祖先是荷兰清教徒,1568年避难来到英国,由于他的讲道吸引许多人,被誉为“清教徒的承
  • 曼萨尔坐标:21°23′49″N 79°15′46″E / 21.396839°N 79.2627341°E / 21.396839; 79.2627341曼萨尔(Mansar),是印度马哈拉施特拉邦Nagpur县的一个城镇。总人口6458(2001年)。该地20
  • 芸薹芸薹(学名:),又称为油菜,是芸薹属的一种植物,可作为叶菜(如小白菜、大白菜、菜心)、根用植物(如芜菁)和作为植物油(非常见的甘蓝型油菜,详见油菜)食用。在十八世纪时,卡尔·林奈视芜菁和油
  • 基塞尔 (加利福尼亚州)基塞尔(英语:Kiesel)是位于美国加利福尼亚州优洛县的一个非建制地区。该地的面积和人口皆未知。基塞尔的座标为38°39′47″N 121°37′00″W / 38.66306°N 121.61667°W / 38
  • 李伟涵李伟涵(1985年8月12日-)台湾作家。阳明高中、东吴大学中文系。网络笔名穆梅。自设有脸书粉丝页面及私人脸书。2002年于九歌出版社出版《希望之石》,出版时年龄为16岁。2005年出
  • 王立彤王立彤(1968年12月-),汉族,安徽巢湖人,1991年5月加入中国共产党,中华人民共和国地方政治人物。1990年7月,毕业于安徽师范大学化学系化学教育专业。1995年7月,毕业于清华大学人文学院思想政治教育专业,获法学硕士学位。历任安徽师范大学化学系教师,浙江省温州市纪委宣教室副主任科员,纪检监察二室副主任科员,纪委宣教室副主任、主任。2001年6月,任浙江省洞头县委常委,县纪委书记。2003年1月,浙江省永嘉县委副书记,县纪委书记。2006年11月,任永嘉县代县长。2007年2月,任永嘉县县长。20