设计模式系列之十八:访问者模式

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

##角色介绍

  • Visitor 抽象访问者:抽象类或接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以访问的
  • ConcreteVisitor 具体访问者:它影响到访问者访问一个类后该怎么干,要做什么事情
  • Element 抽象元素:接口或抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的
  • ConcreteElement 具体元素:实现accept方法,通常是visitor.visit(this),基本上已经是一种模式了
  • ObjectStruture 结构对象:元素生产者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色
    #3.通用源码
    Visitor抽象访问者
public interface IVisitor {
  
	//可以访问哪些对象
	public void visit(ConcreteElement1 el1);
	public void visit(ConcreteElement2 el2);
	
}

具体访问者

public class Visitor implements IVisitor {

	//访问el1元素
	@Override
	public void visit(ConcreteElement1 el1) {
		el1.doSomething();
	}

	//访问el2元素
	@Override
	public void visit(ConcreteElement2 el2) {
		el2.doSomething();
	}

}

抽象元素

public abstract class Element {
   //定义业务逻辑
	public abstract void doSomething();
	//允许谁来访问
	public abstract void accept(IVisitor visitor);
}

具体元素1

public class ConcreteElement1 extends Element {

	//完善业务逻辑
	public void doSomething() {
      //业务处理
	}

	public void accept(IVisitor visitor) {
         visitor.visit(this);
	}

}

具体元素2

public class ConcreteElement2 extends Element {

	//完善业务逻辑
	public void doSomething() {
      //业务处理
	}

	public void accept(IVisitor visitor) {
         visitor.visit(this);
	}

}

结构对象

public class ObjectStruture {

	//对象生成器,这里通过一个工厂方法模式模拟
	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 el = ObjectStruture.createElement();
        	//接收访问者访问
        	el.accept(new Visitor());
		}
	}
}

#4.Demo
看了上面的通用代码,可能并不理解具体的意思,我们来看一个简单的demo,现在有一个公司,公司有普通员工,管理层,现在领导想要查看所有人的报表信息
抽象员工类,即抽象元素

public abstract class Employee {

	public final static int MALE = 0; // 0代表男性
	public final static int FEMALE = 1; // 1代表女性

	private String name; // 名字
	private int Salary; // 薪资
	private int sex; // 性别

	public Employee() {};
	
	public Employee(String name, int salary, int sex) {
	    this.name = name;
	    this.Salary = salary;
	    this.sex = sex;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getSalary() {
		return Salary;
	}

	public void setSalary(int salary) {
		Salary = salary;
	}

	public int getSex() {
		return sex;
	}

	public void setSex(int sex) {
		this.sex = sex;
	}
	
	
	public abstract void accept(IVisitor visitor);

}

普通员工,即具体元素

public class CommonEmployee extends Employee {
   
	private String job;  //工作
	
	public CommonEmployee() {};
	
	public CommonEmployee(String name,int salary,int sex,String job) {
		super(name,salary,sex);
		this.job = job;
	}
	
	
	protected String getOtherInfo() {
		return "工作:"+ this.job + "\t";
	}

	public String getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	//允许访问者访问
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

管理层,即具体元素

public class Manager extends Employee {
   
	private String performance;  //业绩
	
	public Manager() {};
	
	public Manager(String name,int salary ,int sex,String performance) {
		super(name,salary,sex);
		this.performance = performance;
	}
	
	
	protected String getOtherInfo() {
		return "工作:"+ this.performance + "\t";
	}

	public String getPerformance() {
		return performance;
	}

	public void setPerformance(String performance) {
		this.performance = performance;
	}

	//允许的访问者
	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}

抽象访问者

public interface IVisitor {
 
	public void visit(CommonEmployee commonEmployee);
	
	public void visit(Manager manager);
}

具体访问者

public class Visitor implements IVisitor {

	//访问普通员工,打印普通员工报表
	@Override
	public void visit(CommonEmployee commonEmployee) {
           System.out.println(this.getCommonEmployee(commonEmployee));
	}

	//访问部门经理,打印部门经理报表
	@Override
	public void visit(Manager manager) {
           System.out.println(this.getMangerInfo(manager));
	}

	//组装基本信息
	private String getBasicInfo(Employee employee) {
		StringBuffer info = new StringBuffer();
		info.append("姓名:"+employee.getName()+"\t");
		info.append("性别:"+(employee.getSex()==Employee.FEMALE?"女":"男")+"\t");
		info.append("薪资:"+employee.getSalary()+"\t");
		return info.toString();
	}
	
	//组装部门经理信息
	private String getMangerInfo(Manager manager) {
		StringBuffer info = new StringBuffer();
		info.append(this.getBasicInfo(manager));
		info.append("业绩:"+manager.getPerformance());
		return info.toString();
	}
	
	//组装普通员工的信息
	private String getCommonEmployee(CommonEmployee commonEmployee) {
		StringBuffer info = new StringBuffer();
		info.append(this.getBasicInfo(commonEmployee));
		info.append("工作:"+commonEmployee.getJob());
		return info.toString();
	}
}

场景类

public class Client {

	public static void main(String[] args) {
		for (Employee emp : mockEmployee()) {
			//emp.report();
			emp.accept(new Visitor());
		}
		
	}
	
	//模拟出公司的人员情况
	public static List<Employee> mockEmployee(){
		List<Employee> list = new ArrayList<Employee>();
		CommonEmployee zhangsan = new CommonEmployee();
		zhangsan.setName("张三");
		zhangsan.setSalary(8000);
		zhangsan.setSex(Employee.MALE);
		zhangsan.setJob("java程序员");
		list.add(zhangsan);
		
		CommonEmployee lisi = new CommonEmployee();
		lisi.setName("李四");
		lisi.setSalary(7500);
		lisi.setSex(Employee.MALE);
		lisi.setJob("前端");
		list.add(lisi);
		
		CommonEmployee laowang = new CommonEmployee();
		laowang.setName("老王");
		laowang.setSalary(7000);
		laowang.setSex(Employee.MALE);
		laowang.setJob("测试");
		list.add(laowang);
		
		Manager zhaoliu = new Manager("赵六",12000,Employee.MALE,"项目经理");
		list.add(zhaoliu);
		return list;
	}
}

运行结果
这里写图片描述
为什么没有结构角色,因为元素我们在场景类里产生了。
#5.应用场景

  1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就是说迭代器模式已经不能胜任的场景
  2. 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类
  3. 业务规则要求遍历多个不同的对象。迭代器只能访问同类或同接口的数据。访问者模式还可以充当拦截器
    #6.优缺点
    ###优点:
  • 符合单一职责原则
  • 优秀的扩展性
  • 灵活性非常高
    ###缺点
  • 具体元素对访问者公布细节
  • 具体原色变更比较困难
  • 违背了依赖倒置原则
    #7.扩展
    ###7.1 多个访问者
    ###7.2 双分派
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值