访问者模式学习和思考

1.概念
访问者模式(Visitor):表示一个作用于某对象结构中的各元素的操作。它使你在不改变各元素的类的前提下定义作用于这些元素的新操作。

2.理解
2.1 理解核心代码
访问者模式可能是行为类模式中最复杂的一种模式了。压轴戏!我们首先来看一个简单的例子,代码如下:
class A {  
    public void method1(){  
        System.out.println("我是A");  
    }  
      
    public void method2(B b){  
        b.showA(this);
    }  
}  
  
class B {  
    public void showA(A a){  
        a.method1();
    }
}


public class Test {  
    public static void main(String[] args){  
        A a = new A();  
        a.method1();  
        a.method2(new B());  
    }  
}
主要看一下类B的showA方法,showA方法使用类A作为参数,然后调用类A的method1方法,可以看到,method2方法绕来绕去,无非就是调用了一下自己的method1方法而已,它的运行结果应该也是“我是A”。你会说,这不是疯了吗?哪个傻子会这么玩啊?确实啊,我们可以这样分析,类B里面开了一个口子,叫showA()方法,先不管方法的名字,此方法的作用就是让A去访问B,这正好符合OO的开闭原则,不是吗?当只有一个A访问的时候,这样做有点浪费的意思,如果又一个AbstractA抽象类,有A1类,A2类等很多的类都继承AbstractA,而这些子类都要访问B呢?还会觉得这种做法很傻吗?这里就是访问者模式的核心!


2.2 从字面意思来看,访问者模式就是提供让别人来访问的,访问什么呢?前提是假设被访问的对象种类是比较稳定的,一般不会发生变化的。这些不怎么会变化的对象被不同的元素访问,仅此而已。
我们知道,增加一个访问者类型,就需添加一个访问者的类继承visitor,这个跑不了。但是新增类的对象需要访问上面的被访问对象,怎么办呢?按照常规思维,那不就需要在上面的被访问类中添加if else?明显违背了OO原则啊,如果不断增加新的访问对象,那还不被玩死了啊,代码没法法维护了,又要无穷无尽加班了!?使用以上的"口子"就可以实现动态添加访问者,且不会违背OO原则。


3. 访问者模式的构成
在访问者模式中,主要包括下面几个角色:
抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。
访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。
抽象元素类:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。
元素类:实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。
结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。


4. 举例


abstract class Element {  
    public abstract void accept(IVisitor visitor);  
    public abstract void doSomething();  
}  
  
interface IVisitor {  
    public void visit(ConcreteElement1 el1);  
    public void visit(ConcreteElement2 el2);  
}  
  
class ConcreteElement1 extends Element {  
    public void doSomething(){  
        System.out.println("这是元素1");  
    }  
      
    public void accept(IVisitor visitor) {  
        visitor.visit(this);  
    }  
}  
  
class ConcreteElement2 extends Element {  
    public void doSomething(){  
        System.out.println("这是元素2");  
    }  
      
    public void accept(IVisitor visitor) {  
        visitor.visit(this);  
    }  
}  
class Visitor implements IVisitor {  
  
    public void visit(ConcreteElement1 el1) {  
        el1.doSomething();  
    }  
      
    public void visit(ConcreteElement2 el2) {  
        el2.doSomething();  
    }  
}  
  
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 ConcreteElement1());  
            }else{  
                list.add(new ConcreteElement2());  
            }  
        }  
        return list;  
    }  
}  
  
public class Client {  
    public static void main(String[] args){  
        List<Element> list = ObjectStruture.getList();  
        for(Element e: list){  
            e.accept(new Visitor());  
        }  
    }  
}  

5. 其实自己看访问者模式,有双分派技术。第一次是在客户端时,具体是哪一种visitor,第二次是在具体的accept方法时,使用的是哪个方法(将自己作为this传递进去)。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值