定义与结构
访问者模式,顾名思义使用了这个模式后就可以在不修改已有程序结构的前提下,通过添加额外的“访问者”来完成对已有代码功能的提升。《设计模式》一书对于访问者模式给出的定义为:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。从定义可以看出结构对象是使用访问者模式必须条件,而且这个结构对象必须存在遍历自身各个对象的方法。这便类似于java 中的collection 概念了。
以下是访问者模式的组成结构:
1) 访问者角色(Visitor):为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具体访问者的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2) 具体访问者角色(Concrete Visitor):实现每个由访问者角色(Visitor)声明的操作。
3) 元素角色(Element):定义一个Accept 操作,它以一个访问者为参数。
4) 具体元素角色(Concrete Element):实现由元素角色提供的Accept 操作。
5) 对象结构角色(Object Structure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合。
类图
访问者模式的实现
//访问者角色--Visitor
public interface Visitor {
void visit(Gladiolus g);
void visit(Runuculus r);
void visit(Chrysanthemum c);
}
//具体访问者角色--Concrete Visitor1
public class StringVal implements Visitor{
String s;
public String toString() { return s; }
@Override
public void visit(Gladiolus g) {
// TODO Auto-generated method stub
s="Gladiolus";
}
@Override
public void visit(Runuculus r) {
// TODO Auto-generated method stub
s="Runuculus";
}
@Override
public void visit(Chrysanthemum c) {
// TODO Auto-generated method stub
s="Chrysanthemum";
}
}
//具体访问者角色--Concrete Visitor2
public class Bee implements Visitor{
@Override
public void visit(Gladiolus g) {
// TODO Auto-generated method stub
System.out.println("Bee and Gladiolus");
}
@Override
public void visit(Runuculus r) {
// TODO Auto-generated method stub
System.out.println("Bee and Runuculus");
}
@Override
public void visit(Chrysanthemum c) {
// TODO Auto-generated method stub
System.out.println("Bee and Chrysanthemum");
}
}
//元素角色--Element
public interface Flower {
void accept(Visitor v);
}
//具体元素角色--Concrete Element1
public class Runuculus implements Flower{
@Override
public void accept(Visitor v) {
// TODO Auto-generated method stub
v.visit(this);
}
}
//具体元素角色--Concrete Element2
public class Gladiolus implements Flower{
@Override
public void accept(Visitor v) {
// TODO Auto-generated method stub
v.visit(this);
}
}
//具体元素角色--Concrete Element3
public class Chrysanthemum implements Flower{
@Override
public void accept(Visitor v) {
// TODO Auto-generated method stub
v.visit(this);
}
}
//对象结构角色--Object Structure
//这是一个对象生成器,不是一个完整的对象结构,这里仅仅是模拟对象结构中的元素
public 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 {
List flowers = new ArrayList();
public BeeAndFlowers() {
for (int i = 0; i < 10; i++)
flowers.add(FlowerGenerator.newFlower());
}
Visitor sval;
public void test() {
// It's almost as if I had a function to
// produce a Flower string representation:
// 这个地方你可以修改以便使用另外一个具体访问者角色
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[]) {
BeeAndFlowers test=new BeeAndFlowers();
test.test();
}
}
验证输出
Gladiolus
Runuculus
Runuculus
Gladiolus
Gladiolus
Runuculus
Runuculus
Chrysanthemum
Chrysanthemum
Runuculus
总结
使用了访问者模式以后,对于原来的类层次增加新的操作,仅仅需要实现一个具体访问者角色就可以了,而不必修改整个类层次。而且这样符合“开闭原则”的要求。而且每个具体的访问者角色都对应于一个相关操作,因此如果一个操作的需求有变,那么仅仅修改一个具体访问者角色,而不用改动整个类层次。