访问者模式

✍ dations ◷ 2025-07-16 05:06:06 #访问者模式

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

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

参考条目

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


相关

  • J01DA·B·C·D·G·H·QI·J·L·M·N·P·R·S·VATC代码J01(抗菌药)是解剖学治疗学及化学分类系统的一个药物分组,这是由世界卫生组织药物统计方法整合中心(The WHO Collaboratin
  • 阿伏伽德罗常量在物理学和化学中,阿伏伽德罗常数(符号: N A {\displaystyle N_{A}} 或
  • 阿普特1法国统计部门在计算土地面积时,不计算面积大于1平方公里的湖泊、池塘、冰川和河口。阿普特(法语:Apt,发音:)是法国普罗旺斯-阿尔卑斯-蓝色海岸大区 沃克吕兹省的一个市镇,位于该省
  • 1,1-二(氯甲基)乙烯1,1-二(氯甲基)乙烯是一种有机化合物,化学式为CH2=C(CH2Cl)2,它有两个烯丙基氯,是一种双烷基化试剂。它可由季戊四醇为原料来合成,其第一步反应是对其氯化。它可以和九羰基二铁
  • 金田美穗金田美穗(日语:金田 美穂,7月11日-),日本女性配音员。现在是自由身,以前经历大阪TV talent bureau。AB型血。为人熟悉的代表配音作品是SNK电玩格斗游戏《侍魂》系列的绯雨闲丸和《
  • 美国国务卿列表美国国务卿列表,列举美国历任外交部长、国务卿及其代理。  联邦党  民主共和党  民主党  辉格党  共和党注1在这些标注的总统失去履行职责的能力后,当时的国务卿曾
  • 通淮宫通淮宫位于基隆,民国38年(1949年)开宫,一开始是几位小童于山谷中内发现神像数座,于是当地居民便在崖壁边径行设坛朝供,期间屡遭当地教会百般刁难,但当地民众结合耆老、仕绅,仍极力争
  • 利夫希茨利夫希茨或利弗席兹(俄语:Ли́фшиц,Lifshitz)是一个中欧、东欧姓氏,可能来自于波兰、捷克边境上的格武布奇采。其拼写变体很多(参见Lifschitz(英语:Lifschitz));就译名而言,变体有
  • 勒达·科斯米德斯勒达·科斯米德斯(英语:Leda Cosmides,1957年5月9日-),出生于宾夕法尼亚州费城,是一名美国心理学家,与丈夫约翰·托比人类学家帮助发展演化心理学领域。她最初在哈佛大学拉德克利夫
  • 隆姓隆姓(隆 古音:lum 力中切)是中文姓氏之一,在《百家姓》中排第368位。在现代它是极罕见的姓氏。《姓氏考略》记载,春秋时鲁国有隆邑,当地人有以邑名为姓氏的。