设计模式20-访问者模式

访问者模式
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
优点:
1、符合单一职责原则,具体元素角色负责数据的加载,而Visitor类则负责报表的展现,两个不同的职责非常明确的分离开,各自演绎变化;
2、优秀的扩展性,由于职责分开,继续增加对数据的操作是非常快的;
3、灵活性非常高。
缺点:
1、具体元素对访问者公布细节;
2、具体元素变更比较困难;
3、违背了依赖倒置原则,访问者依赖的是具体元素,而不是抽象元素,破坏了依赖倒置原则。
使用场景:
1、一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,
也就是用迭代器模式已经不能胜任的情景;
2、需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些类的对象。

//抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以被访问的。
public interface IVisitor {
	public void visit(ConcreteElement1 e);
	public void visit(ConcreteElement2 e);
}
//具体访问者:它影响访问者访问到一个类后该怎么干,要做什么事情
public class ConcreteVisitor implements IVisitor {
	@Override
	public void visit(ConcreteElement1 e) {
		e.doSomething();
	}
	@Override
	public void visit(ConcreteElement2 e) {
		e.doSomething();
	}
}
//抽象元素类:接口或抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。
public abstract class Element {
	public abstract void doSomething();
	public abstract void accept(IVisitor visitor);
}
//具体元素1:实现accept方法,通常是visitor.visit(this),基本上都形成一种模式了
public class ConcreteElement1 extends Element {
	@Override
	public void doSomething() {
		
	}
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}

}
public class ConcreteElement2 extends Element {
	@Override
	public void doSomething() {
	}
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
//结构对象:元素产生者,一般容纳在多个不同类、不同接口的容器,如list、set、map等,在项目中一般很少抽象出这个角色。
public class ObjectStructure {
	public static Element createElement(){
		Random random = new Random();
		if (random.nextInt(100) > 50) {
			return new ConcreteElement1();
		}else{
			return new ConcreteElement2();
		}
	}
}
public class Client {
	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			Element element = ObjectStructure.createElement();
			element.accept(new ConcreteVisitor());
		}
	}
}
//扩展
public abstract class AbsActor {
	public void act(Role role){
		System.out.println("演员可以演任意角色");
	}
	public void act(KungFuRole kungFuRole){
		System.out.println("演员都可以演功夫角色");
	}
}
//演员要扮演的角色
public interface Role {

}
//青年演员
public class YoungActor extends AbsActor {
	@Override
	public void act(KungFuRole kungFuRole) {
		System.out.println("最喜欢演功夫角色");
	}
}
public class OlderActor extends AbsActor {
	@Override
	public void act(KungFuRole kungFuRole) {
		System.out.println("年龄大了,不能演功夫角色");
	}
}
//傻子角色
public class IdiotRole implements Role{

}
//功夫角色
public class KungFuRole implements Role{

}
public class Client {

	public static void main(String[] args) {
		//定义一个演员
		AbsActor absActor = new OlderActor();
		//定义一个角色
		Role role = new KungFuRole();
		//开始演戏
		absActor.act(role);
		absActor.act(new KungFuRole());
		/**
		 * 可以看到,重载在编译器就决定了调用哪个方法,它是根据role的表面类型而决定的,这是静态绑定;
		 * 而Actor的执行方法act则是由实际类型决定的,这是动态绑定。
		 * 使用访问者模式可以实现:不管演员类和角色类怎么变化,我们都能找到期望的方法运行,这就是双分派,
		 * 双分派意味着得到执行的操作决定于请求的种类和两个接收者的类型。
		 * 
		 */
	}

}


 

猜你喜欢

转载自blog.csdn.net/zhuozi0810/article/details/89316472
今日推荐