Visitor模式,在不修改已有程序结构的前提下,通过添加额外的“访问者”来完成对已有代码功能的提升。
Visitor模式的组成结构:
1) 访问者角色(Visitor):声明一个访问接口。接口的名称和方法的参数标识了向访问者发送请求的元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2) 具体访问者角色(Concrete Visitor):实现访问者角色(Visitor)接口
3) 元素角色(Element):定义一个Accept操作,它以一个访问者为参数。
4) 具体元素角色(Concrete Element):实现元素角色(Element)接口。
5) 对象结构角色(Object Structure):这是使用Visitor模式必须的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口允许访问者角色访问它的元素;可以是一个组合(组合模式)或是一个集合,如一个列表或一个无序集合。
类图如下:
代码例子:
interface Visitor {
void visit(Gladiolus g);
void visit(Runuculus r);
void visit(Chrysanthemum c);
}
interface Flower {
void accept(Visitor v);
}
// concrete element
class Gladiolus implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
class Runuculus implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
class Chrysanthemum implements Flower {
public void accept(Visitor v) { v.visit(this);}
}
// concrete visitor
class StringVal implements Visitor {
String s;
public String toString() { return s; }
public void visit(Gladiolus g) {
s = "Gladiolus";
}
public void visit(Runuculus r) {
s = "Runuculus";
}
public void visit(Chrysanthemum c) {
s = "Chrysanthemum";
}
}
// concrete visitor
class Bee implements Visitor {
public void visit(Gladiolus g) {
System.out.println("Bee and Gladiolus");
}
public void visit(Runuculus r) {
System.out.println("Bee and Runuculus");
}
public void visit(Chrysanthemum c) {
System.out.println("Bee and Chrysanthemum");
}
}
//这是一个对象生成器
class FlowerGenerator {
private static Random rand = new Random();
public static Flower newFlower() {
switch(rand.nextInt(3)) {
default:
case 0: return new Gladiolus();
case 1: return new Runuculus();
case 2: return new Chrysanthemum();
}
}
}
//客户测试程序
public class BeeAndFlowers extends TestCase {
/*
首先在客户端先获得一个具体的访问者角色
遍历对象结构
对每一个元素调用accept方法,将具体访问者角色传入
这样就完成了整个过程
*/
List flowers = new ArrayList();
public BeeAndFlowers() {
for(int i = 0; i < 10; i++)
flowers.add(FlowerGenerator.newFlower());
}
Visitor sval ;
public void test() {
sval = new StringVal();
Iterator it = flowers.iterator();
while(it.hasNext()) {
((Flower)it.next()).accept(sval);
System.out.println(sval);
}
}
public static void main(String args[]) {
junit.textui.TestRunner.run(BeeAndFlowers.class);
}
}