访问者模式是23种设计模式中最复杂的一个,使用频率并不高,一般不需要用,如果你一旦需要使用,那就是真的需要了。
它是一种将数据操作和数据结构分离的设计模式。
定义
封装一些作用于某种数据结构中的各元素操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。
使用场景
1.对象结构比较稳定,但经常需要再次对象结构上定义新的操作。
2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
来看一个实现
企业业绩考核,有工程师和经理两种职工,老板有CEO和CTO,CTO只关心工程师的代码数量、经理的产品数量。CEO关心工程师和经理的KPI。
于是我们定一个staff员工基类,有一个抽象方法accept(Visitor visitor),他有两个子类Engineer和Mnager,他们实现了accept(Visitor visitor)方法,并且在accept方法中调用visitor.visit(this);
而Visitor类中的visit方法有两个重载一个是visit(Engineer)另一个是visit(Manager),而Visitor类两个子类CTO和CEO两个类在实现这两个visit方法的时候去根据需求来访问不同的数据就行了。
最后有一个中的报表类,类里面用例如List存储了所有员工的资料,然后有一个showReport(Visitor visitor)方法,方法里面遍历所有员工accpet并传入visitor。
每一个对象的accept(Visitor)调用了visitor.visit(this)方法,visitor中又根据传过来的this判断是哪个对象去获取需要的数据。
这就是一个访问者模式的简单实现,其实也还是不难的。
Android源码中的访问者模式
编译时注解依赖于APT(Annotation Processing Tools)实现,在编译器会自己生成相关的java类。
注解可以指定作用于哪种元素上, 比如:
PackageElement,包元素
TypeElement,类型元素
ExecutableElement,可执行元素
VariableElement,变量元素
TypeParameterElement,类型参数元素
Element基类里面有一个accept(ElementVisitor<R,p> v,P p)方法
ElementVisitor里面又根据不同的元素类型重载很很多visit方法。
比如类型元素访问者 里面是visitType(TypeElement e,P p)方法,然后里面做了这种类型元素需要的操作。
显然这就是一个访问者模式。
优点:
1.角色职责分离,符合单一职责原则。
2.具有优秀的扩展性。
3.使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化。
4.灵活性。
缺点:
1.具体元素对访问者公布细节,违反了迪米特原则
2.具体元素变更时,修改成本大
3.违反了依赖倒置原则,为了区别对待而依赖了具体类,而不是依赖抽象。