访问者模式
访问者模式是一种对象行为型模式,,访问者模式就是一种分离对象数据结构与行为的方法,通过这种分离,可达到为一个被访问者动态添加新的操作而无需做其它的修改的效果。
定义
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
使用场景
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中。当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
- 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
结构
实现
public interface Visitor {
void visitConcreteElementA(ConcreteElementA elementa);
void visitConcreteElementB(ConcreteElementB elementb);
}
public class ConcreteVisitor1 implements Visitor {
public void visitConcreteElementA(ConcreteElementA elementa) {
elementa.operationA();
}
public void visitConcreteElementB(ConcreteElementB elementb) {
elementb.operationB();
}
}
public class ConcreteVisitor2 implements Visitor {
public void visitConcreteElementA(ConcreteElementA elementa) {
elementa.operationA();
}
public void visitConcreteElementB(ConcreteElementB elementb) {
elementb.operationB();
}
}
public interface Element {
void accept(Visitor v);
}
public class ConcreteElementA implements Element{
public void accept(Visitor v) {
v.visitConcreteElementA(this);
}
public void operationA(){
System.out.println("operationA");
}
}
public class ConcreteElementB implements Element{
public void accept(Visitor v) {
v.visitConcreteElementB(this);
}
public void operationB(){
System.out.println("operationB");
}
}
public class ObjectStruture {
public static List<Element> getList(){
List<Element> list = new ArrayList<Element>();
Random ran = new Random();
for(int i=0; i<10; i++){
int a = ran.nextInt(100);
if(a>50){
list.add(new ConcreteElementA());
}else{
list.add(new ConcreteElementB());
}
}
return list;
}
}
测试
public class Client {
public static void main(String[] args){
List<Element> list = ObjectStruture.getList();
for(Element e: list){
e.accept(new ConcreteVisitor1());
}
}
}
优点
符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,所以当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。
扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。
缺点
增加新的元素类比较困难。通过访问者模式的代码可以看到,在访问者类中,每一个元素类都有它对应的处理方法,也就是说,每增加一个元素类都需要修改访问者类(也包括访问者类的子类或者实现类),修改起来相当麻烦。也就是说,在元素类数目不确定的情况下,应该慎用访问者模式。所以,访问者模式比较适用于对已有功能的重构,比如说,一个项目的基本功能已经确定下来,元素类的数据已经基本确定下来不会变了,会变的只是这些元素内的相关操作,这时候,我们可以使用访问者模式对原有的代码进行重构一遍,这样一来,就可以在不修改各个元素类的情况下,对原有功能进行修改。