訪問者模式(Visitor),表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。
舉例:
有的節假日,公司會安排員工一起去戶外進行一些小遊戲,每個遊戲中,男女同事的任務形式也不同,比如吹氣球,其中男同事需要用嘴吹,女同事用打氣筒;騎自行車帶人,男同事負責騎車,女同事負責坐在後面等。這個情景就可以用訪問者模式來實現,男同事和女同事就是兩個不同的元素,每種遊戲都是一個訪問者。
- 元素類
abstract class Person {
String name;
public Person(String name) {
this.name = name;
}
abstract void play(Game game);
}
// 男同事類
class ManWorkmate extends Person {
public ManWorkmate(String name) {
super(name);
}
@Override
void play(Game game) {
game.acceptManGame(this);
}
}
// 女同事類
class WomanWorkmate extends Person {
public WomanWorkmate(String name) {
super(name);
}
@Override
void play(Game game) {
game.acceptWomenManGame(this);
}
}
- 訪問者,即各種遊戲
abstract class Game {
abstract void acceptManGame(Person person);
abstract void acceptWomenManGame(Person person);
}
// 吹氣球
class BallonGame extends Game {
@Override
void acceptManGame(Person person) {
System.out.println("男同事:" + person.name + " ,吹氣球啦!");
}
@Override
void acceptWomenManGame(Person person) {
System.out.println("女同事:" + person.name + " ,用打氣筒吹氣球啦!");
}
}
// 騎自行車
class BikeGame extends Game {
@Override
void acceptManGame(Person person) {
System.out.println("男同事:" + person.name + " ,準備騎自行車啦!");
}
@Override
void acceptWomenManGame(Person person) {
System.out.println("女同事:" + person.name + " ,準備坐在自行車後座啦!");
}
}
- 對象結構,針對不同的遊戲遍歷參與遊戲的同事,得到不同的反應
class ObjectStructure {
List<Person> elements = new ArrayList<>();
void add(Person person) {
elements.add(person);
}
void del(Person person) {
elements.remove(person);
}
void beginGame(Game game){
for (Person person : elements) {
person.play(game);
}
}
}
- 主程序
class Test {
public static void main(String[] args) {
ObjectStructure o = new ObjectStructure();
Person xiaoLi = new ManWorkmate("小李");
Person xiaoWang = new WomanWorkmate("小王");
Person xiaoZhang = new ManWorkmate("小張");
Person xiaoZhao = new WomanWorkmate("小趙");
o.add(xiaoLi);
o.add(xiaoWang);
o.add(xiaoZhang);
o.add(xiaoZhao);
System.out.println("進行第一項遊戲:吹氣球");
Game game1 = new BallonGame();
o.beginGame(game1);
System.out.println("======");
System.out.println("進行第二項遊戲:騎自行車");
Game game2 = new BikeGame();
o.beginGame(game2);
}
}
結果:
進行第一項遊戲:吹氣球
男同事:小李 ,吹氣球啦!
女同事:小王 ,用打氣筒吹氣球啦!
男同事:小張 ,吹氣球啦!
女同事:小趙 ,用打氣筒吹氣球啦!
======
進行第二項遊戲:騎自行車
男同事:小李 ,準備騎自行車啦!
女同事:小王 ,準備坐在自行車後座啦!
男同事:小張 ,準備騎自行車啦!
女同事:小趙 ,準備坐在自行車後座啦!
如果需要再增加遊戲方式,只需要再增加一個Game
子類,在主程序中,調用
Game game3 = new OtherGame();
o.beginGame(game3);
就可以實現。
總結
訪問者模式適用於數據結構相對穩定的系統,它把數據結構和作用於結構上的操作之間的耦合解脫開,使得操作集合可以相對自由地演化。
訪問者模式的目的是要把處理從數據結構分離出來。如果一個系統有比較穩定的數據結構,又有易於變化的算法的話,使用訪問者模式就比較合適,因爲訪問者模式使得算法操作的增加變得容易。
訪問者結構的缺點就是使增加新的數據結構變得困難了。GoF的一個作者就說過:“大多數時候你並不需要訪問者模式,但當一旦你需要訪問者模式時,那就是真的需要它了。”事實上,我們很難找到數據結構不變的情況,所以使用訪問者模式的機會也就不太多。