访问者模式
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
访问者模式涉及的角色
(1)抽象访问者角色(Visitor):声明了一个或者多个访问操作,形成所有的集体元素角色必须实现的接口
(2)具体访问者角色(ConcreteVisitor):实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
(3)抽象节点角色(Node):声明一个接受操作,接受一个访问者对象作为一个参量。
(4)具体节点角色(Node):实现了抽象元素所规定的接受操作。
(5)结构对象角色(ObjectStructure):可以遍历结构中所有的元素;如果需要,提供一个高层次的接口让访问者对象可以访问每一个元素;如果需要,可以设计成一个复合对象或一个集合,如(List)或(Set)。
访问模式的优点
访问者模式使得增加新的操作比较容易,增加新的操作只要增加新的访问者类;
访问者模式将有关的行为封装到一个访问对象中,而不是分散到一个个元素类中;
访问者模式可以跨过几个类的等级结构访问属于不同等级结构的成员变量;
累积状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己的内部,而不是分散到很多的元素对象中, 易于系统维护。
缺点
增加新的元素类变得很困难。每增加一个新的元素都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体的访问者类中增加相应的具体操作;
破坏封装性。访问者模式要求访问对象访问并调用每一个元素对象的操作,这隐含了一个队所有元素对象的要求,即必须暴露一些自己的操作和内部状态,否则访问者的访问就变得毫无意义。由于访问者对象自己会累积访问操作所需要的状态,从而使得这些状态不再存储在元素对象中,破坏类的封装性;
违背了依赖倒置原则。访问者依赖的是具体的元素,而不是抽象的元素。特别是在面向对象的编程中,抛弃了对接口的依赖,而直接依赖实现类,扩展比较困难。
package visitor;
/**
* 抽象元素,该角色什么一个操作,接收一个访问者
* @author 21409262
*
*/
public interface Element {
//接收一个访问者
public void accept(Visitor visitor);
}
package visitor;
/**
* 具体元素
*
*/
public class ConcreteElementA implements Element {
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
//把自己传给访问者,在外界看来只要调用访问者对象,访问者对象
//内部再通过这个传入的元素对象执行元素对象的方法
visitor.visit(this);
}
//业务逻辑方法
public void operation(){
System.out.println("访问元素1");
}
}
package visitor;
/**
* 具体元素
*
*/
public class ConcreteElementB implements Element {
@Override
public void accept(Visitor visitor) {
// TODO Auto-generated method stub
//把自己传给访问者,在外界看来只要调用访问者对象,访问者对象
//内部再通过这个传入的元素对象执行元素对象的方法
visitor.visit(this);
}
//业务逻辑方法
public void operation(){
System.out.println("访问元素1");
}
}
package visitor;
public interface Visitor {
//可以访问哪些元素
public void visit(ConcreteElementA elA);
public void visit(ConcreteElementB elB);
}
package visitor;
public class ConcreteVisitor implements Visitor {
@Override
public void visit(ConcreteElementA elA) {
// TODO Auto-generated method stub
elA.operation();
}
@Override
public void visit(ConcreteElementB elB) {
// TODO Auto-generated method stub
elB.operation();
}
}
package visitor;
import java.util.Random;
import java.util.Vector;
/**
* 结构对象角色,可以遍历结构中的所元素
*
*/
public class OjbectStructure {
private Vector<Element> elements;
//构造函数
public OjbectStructure(){
elements = new Vector<Element>();
}
//添加先元素
public void add(Element el){
elements.add(el);
}
//执行访问动作
public void action(Visitor v){
for(Element el:elements){
el.accept(v);
}
}
//元素生成器,这里通过一个工厂方法进行模拟
public void createElements(){
Random rand = new Random();
for(int i=0;i<10;i++){
if(rand.nextInt(100) > 50){
//添加新元素1
this.add(new ConcreteElementA());
}else{
this.add(new ConcreteElementB());
}
}
}
}
package visitor;
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建一个结构对象
OjbectStructure os = new OjbectStructure();
//生成元素
os.createElements();
//创建每一个访问者对象
Visitor visitor = new ConcreteVisitor();
os.action(visitor);
}
}