实验室有个项目用到了访问者模式, 现在需要从项目中分离一些东西, 所以上网搜了一下访问者模式
百度百科中:
访问者的定义(源于GoF《Design Pattern》):表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
对象结构这个名词一开始不太理解, 姑且看做是一个对象的集合吧, 类似于Collection之类的可以遍历其中元素的集合吧.
这个模式中涉及到的角色:
1.Visitor 抽象访问者角色,为该对象结构中具体元素角色声明一个访问操作接口。该操作接口的名字和参数标识了发送访问请求给具休访问者的具休元素角色,这样访问者就可以通过该元素角色的特定接口直接访问它。
2.ConcreteVisitor.具体访问者角色,实现Visitor声明的接口。
3.Element 定义一个接受访问操作(accept()),它以一个访问者(Visitor)作为参数。
4.ConcreteElement 具体元素,实现了抽象元素(Element)所定义的接受操作接口。
5.ObjectStructure 结构对象角色,这是使用访问者模式必备的角色。它具备以下特性:能枚举它的元素;可以提供一个高层接口以允许访问者访问它的元素;如有需要,可以设计成一个复合对象或者一个聚集(如一个列表或无序集合)。
来看一张访问者模式的类图
根据另外一篇文章的用junit写的代码修改了一下,写了个例子:
这里对象有两种Daisy和Lilac,都实现了Flower接口
Flower接口:
package visited;
import visitor.Visitor;
public interface Flower {
//接受访问者作为参数
public void accept(Visitor v);
}
Daisy和Lilac的实现:
package visited;
import visitor.Visitor;
public class Daisy implements Flower {
private String name="daisy";
@Override
public void accept(Visitor v) {
//调用访问者的访问方法,并传递对象本身作为参数, 完成第二次分派
v.visit(this);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package visited;
import visitor.Visitor;
public class Lilac implements Flower {
private String name="lilac";
@Override
public void accept(Visitor v) {
//调用访问者的访问方法,并传递对象本身作为参数, 完成第二次分派
v.visit(this);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
访问者接口Visitor:
package visitor;
import visited.Daisy;
import visited.Lilac;
//访问者接口
public interface Visitor {
public void visit(Lilac s);
public void visit(Daisy hr);
}
这里只定义了一个具体访问者, BeeVisitor:
package visitor;
import visited.Daisy;
import visited.Lilac;
//具体的访问者
public class BeeVisitor implements Visitor {
@Override
public void visit(Lilac s) {//实现visit方法
System.out.println("Bee is visiting "+s.getName());
}
@Override
public void visit(Daisy hr) {
System.out.println("Bee is visiting "+hr.getName());
}
}
下面是测试程序:
package test;
import java.util.ArrayList;
import java.util.List;
import visited.Daisy;
import visited.Flower;
import visited.Lilac;
import visitor.BeeVisitor;
public class VisitorTest {
public static void main(String[] args){
//定义对象结构
List<Flower> flowers=new ArrayList<Flower>();
for(int i=0;i< 4; i++){
if(i%2==0)
flowers.add(new Daisy());
else
flowers.add(new Lilac());
}
//访问
for(int i=0; i<4; i++){
//对象接受访问者,完成了第一次分派
flowers.get(i).accept(new BeeVisitor());
}
}
}
运行结果如下:
Bee is visiting daisy
Bee is visiting lilac
Bee is visiting daisy
Bee is visiting lilac
首先定义了一个对象结构: flowers, 里面包含很多对象, 这符合设计模式中对对象结构的定义,它可以遍历它所包含的元素.
然后对每个对象结构中的元素进行访问, 对象接受访问者, 完成了第一次分派; 在accept()方法中, 调用了访问者的visit()方法, 并传递对象本身作为参数, 完成了第二次分派
实现了访问者模式的双重分派
我知道的一个用到访问者模式的项目: PMD 这是一个Java代码测试项目, 对于抽象语法树各节点的访问用的就是访问者模式