訪問者模式

訪問者模式是一種將演算法與物件結構分離的軟體設計模式。

這個模式的基本想法如下：首先我們擁有一個由許多物件構成的物件結構，這些物件的類都擁有一個 accept 方法用來接受訪問者物件；訪問者是一個介面，它擁有一個 visit 方法，這個方法對訪問到的物件結構中不同型別的元素作出不同的反應；在物件結構的一次訪問過程中，我們遍歷整個物件結構，對每一個元素都實施 accept 方法，在每一個元素的 accept 方法中回撥訪問者的 visit 方法，從而使訪問者得以處理物件結構的每一個元素。我們可以針對物件結構設計不同的實在的訪問者類來完成不同的操作。

訪問者模式使得我們可以在傳統的單分派語言（如 Smalltalk、Java 和 C++）中模擬雙分派技術。對於支援多分派的語言（如 CLOS），訪問者模式已經內置於語言特性之中了，從而不再重要。

Python 的例子

"""Visitor pattern example."""

from abc import ABCMeta, abstractmethod

NOT_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 =

Wheel ("front left"), Wheel ("front right"),

Wheel ("back left"), Wheel ("back right"),

Body , Engine

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

一個實際的例子

這個例子是 Htmlparser 計劃裡的一段示例。為獲得一個 Web 頁面的所有內容，採用如下的方式使用類 TextExtractingVisitor:

Parser parser = new Parser ("http://pageIwantToParse.com");

TextExtractingVisitor visitor = new TextExtractingVisitor ;

parser.visitAllNodesWith (visitor);

System.out.println (visitor.getExtractedText );