Java设计模式(十八)---访问者模式

x33g5p2x  于2021-03-13 发布在 Java  
字(5.7k)|赞(0)|评价(0)|浏览(180)

定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

一般模式

Visitor----抽象访问者
--|抽象类或接口,声明访问者可以访问那些元素,具体到程序中的就是visit的参数定义那些对象是可以被访问的。
ConcreteVisotor---抽象元素
---|他影响访问者访问到类后,该怎么做,要做什么事情。
Element---抽象元素
--|接口或者抽象类,声明接受哪一类访问者访问,程序上通过accept方法中的参数定义
ConcreteElement---具体元素
--|实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了。
ObjectStruture---结构对象

--|元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。

public class VisitorTest {
	public static void main(String[] args) {
		//产生10个具体元素对象
		for(int i=0;i<10;i++){
			Element e = ObjectStruture.createElement();
			//接收访问者访问
			e.accept(new ConcreteVisitor());
		}
	}
}
/**
 * 抽象元素类
 * 除了有自己的业务逻辑外,
 * 定义哪一类的访问者,可以访问。
 * @author admin
 *
 */
abstract class Element{
	//执行自身的业务逻辑
	public abstract void doSomenthing();
	//定义访问者都有哪些
	public abstract void accept(IVisitor visitor);
}
/**
 * 具体的实现元素类。
 * 1、实现自身的具体业务逻辑
 * 2、设置哪个访问者可以访问
 * @author admin
 *
 */
class ConcreteElement1 extends Element{
	@Override
	public void doSomenthing() {
		System.out.println("我是元素1的具体实现者...");
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
/**
 * 具体的实现元素类。
 * 1、实现自身的具体业务逻辑
 * 2、设置哪个访问者可以访问
 * @author admin
 *
 */
class ConcreteElement2 extends Element{
	@Override
	public void doSomenthing() {
		System.out.println("我是元素2的具体实现者...");
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
/**
 * 抽象访问者,
 * 声明访问者可以访问哪些类。具体的执行方法有子类去实现
 * @author admin
 *
 */
interface IVisitor{
	//定义访问ConcreteElement1类的具体实现
	public void visit(ConcreteElement1 con1);
	//定义访问ConcreteElement2类的具体实现
	public void visit(ConcreteElement2 con2);
}
/**
 * 访问者的具体实现类,
 * 访问者访问到类以后,做什么事情,有该类来具体实现
 * @author admin
 *
 */
class ConcreteVisitor implements IVisitor{
	@Override
	public void visit(ConcreteElement1 con1) {
		con1.doSomenthing();
		System.out.println("----访问者1号,执行任务");
	}

	@Override
	public void visit(ConcreteElement2 con2) {
		con2.doSomenthing();
		System.out.println("----访问者2号,执行任务");
	}
}
/**
 * 元素的产生者,用于产生被访问者类型的对象。
 * @author admin
 *
 */
class ObjectStruture{
	//利用一个随机数,产生实现类1和2的对象
	public static Element createElement(){
		Random random = new Random();
		if(random.nextInt(100)>50){
			return new ConcreteElement1();
		}
		return new ConcreteElement2();
	}
}

一个例子

一个公司有普通员工和经理,他们都有:姓名、性别、薪水。
私有属性:员工:job(工作),经理:performance(业绩)。
这里需要打印一堆报表,要求员工和经理的相互区分。如何设计合理呢?

public class VisitorT {
	public static void main(String[] args) {
		//打印公司员工的报表
		for(Emploee e : mockEmploy()){
			e.accept(new EmployeeVisitor());
		}
	}
	//模拟公司所有的人员。
	public static List<Emploee> mockEmploy(){
		List<Emploee> employeeList = new ArrayList<Emploee>();
		//创建一些普通员工
		Employer common1 = new Employer();
		common1.setName("lz");
		common1.setJob("APP应用上市..");
		common1.setSalary(12000);
		common1.setSex(1);
		Employer common2 = new Employer();
		common2.setName("ly");
		common2.setJob("APP应用上市..");
		common2.setSalary(11000);
		common2.setSex(1);
		Employer common3 = new Employer();
		common3.setName("ht");
		common3.setJob("美工做好..");
		common3.setSalary(10000);
		common3.setSex(2);
		
		//定义一个经理
		Manager m = new Manager();
		m.setName("lzl");
		m.setPerformence("今天晚上一定加班...");
		m.setSalary(1000000);
		m.setSex(1);
		
		//添加
		employeeList.add(common3);
		employeeList.add(common1);
		employeeList.add(common2);
		employeeList.add(m);
		return employeeList;
	}
}
/**
 * 抽象的员工报表类,
 * 定义共有的属性方法。
 * 并提供一个观察者类的接口
 * @author admin
 *
 */
abstract class Emploee{
	private String name;
	private int sex;
	private double salary;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getSex() {
		return sex;
	}
	public void setSex(int sex) {
		this.sex = sex;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public abstract void accept(IEmployeeVisitor visitor);
}
/**
 * 经理类的具体实现类。
 * @author admin
 *
 */
class Manager extends Emploee{
	//经理关注的是公司业绩
	private String performence;

	public String getPerformence() {
		return performence;
	}
	public void setPerformence(String performence) {
		this.performence = performence;
	}
	
	@Override
	public void accept(IEmployeeVisitor visitor) {
		visitor.visit(this);
	}
}
/**
 * 普通员工的具体实现类。
 * @author admin
 */
class Employer extends Emploee{
	//普工关注的是工作
	private String job;

	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	
	@Override
	public void accept(IEmployeeVisitor visitor) {
		visitor.visit(this);
	}
}
/**
 * 报表观察者接口类,
 * 设置观察者观察具体的实现类。
 * 具体的实现方法,由实现类来完成
 * @author admin
 *
 */
interface IEmployeeVisitor{
	//设置观察普通员工
	public void visit(Employer employer);
	//设置观察经理
	public void visit(Manager manager);
}
/**
 * 具体的观察者实现类,
 * 实现类中观察到被观察者,之后需要打印报表。
 * @author admin
 *
 */
class EmployeeVisitor implements IEmployeeVisitor{

	@Override
	public void visit(Employer employer) {
		System.out.println(this.getEmployerInfo(employer));
	}

	@Override
	public void visit(Manager manager) {
		System.out.println(this.getManageInfo(manager));
	}
	//获取员工的基本共有信息
	private String getBaseInfo(Emploee e){
		String info = "姓名:"+e.getName()+"\t性别:"+
					(e.getSex()==1 ? "男" : "女")+"\t薪水:"+e.getSalary();
		return info;
	}
	//获取经理的所有信息
	private String getManageInfo(Manager m){
		String info = m.getPerformence();
		return info+"\t"+getBaseInfo(m);
	}
	//获取普通员工的全部信息
	private String getEmployerInfo(Employer e){
		String info = e.getJob();
		return info+"\t"+getBaseInfo(e);
	}
}

访问者模式的扩展
---|统计功能

interface IEmployeeVisitor{
	//设置观察普通员工
	public void visit(Employer employer);
	//设置观察经理
	public void visit(Manager manager);
	//统计薪水功能
	public void totalSalary();
}
/**
 * 具体的观察者实现类,
 * 实现类中观察到被观察者,之后需要打印报表。
 * @author admin
 *
 */
class EmployeeVisitor implements IEmployeeVisitor{
	//经理总共薪资
	private double totalManager=0;
	//普通员工薪资
	private double totalEmployer=0;
	@Override
	public void visit(Employer employer) {
		this.getEmployer(employer);
	}

	@Override
	public void visit(Manager manager) {
		this.getManagerSalary(manager);
	}
	//统计总共的薪水
	@Override
	public void totalSalary() {
		System.out.println( "公司一年支付的薪水是:"+this.totalEmployer + this.totalManager);
	}
	//统计经理的薪水
	private void getManagerSalary(Manager m){
		this.totalManager = this.totalManager + m.getSalary();
	}
	//统计员工的薪水
	private void getEmployer(Employer e){
		this.totalEmployer = this.totalEmployer + e.getSalary();
	}
}

访问者模式的优点:
符合单一职责原则
优秀的扩展性
灵活性非常高
访问者模式的缺点:
具体元素对访问者公布细节
具体元素变更比较困难
违背了依赖倒置原则

相关文章