* 24种设计模式——访问者模式

本文介绍访问者模式的概念、实现及应用场景。通过实例演示如何利用访问者模式分离数据和操作,提高代码扩展性和维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

一、访问员工信息


1. 访问者接口

public interface IVisitor {
	//首先,定义我可以访问普通员工
	public void visit(CommonEmployee commonEmployee);
	//其次,定义我还可以访问部门经理
	public void visit(Manager manager);
}
2. 访问者实现

public class Visitor implements IVisitor{
	//访问普通员工,打印出报表
	public void visit(CommonEmployee commonEmployee) {
		System.out.println(this.getCommonEmployee(commonEmployee));
	}
	//访问部门经理,打印出报表
	public void visit(Manager manager) {
		System.out.println(this.getManagerInfo(manager));
	}
	//组装出基本信息
	private String getBasicInfo(Employee employee){
		String info = "姓名:"+employee.getName()+"\t";
		info = info+"性别:"+(employee.getSex()==Employee.FEMALE?"女":"男")+"\t";
		info = info+"薪水:"+employee.getSalary()+"\t";
		return info;
	}
	//组装出部门经理的信息
	private String getManagerInfo(Manager manager){
		String basicInfo = this.getBasicInfo(manager);
		String otherInfo = "业绩:"+manager.getPerformance()+"\t";
		return basicInfo + otherInfo;
	}
	//组装出普通员工信息
	private String getCommonEmployee(CommonEmployee commonEmployee){
		String basicInfo = this.getBasicInfo(commonEmployee);
		String otherInfo = "工作:"+commonEmployee.getJob()+"\t";
		return basicInfo + otherInfo;
	}
}
3. 抽象员工类

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;
	get()/set();
	//我允许一个访问者访问
	public abstract void accept(IVisitor visitor);
}
4. 普通员工

public class CommonEmployee extends Employee{
	//工作内容,这非常重要,以后的职业规划就是靠它了
	private String job;
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	//我允许访问者访问
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
5. 管理层员工

public class Manager extends Employee{
	//这类人物的职责非常明确:业绩
	private String performance;
	public String getPerformance() {
		return performance;
	}
	public void setPerformance(String performance) {
		this.performance = performance;
	}
	//部门经理允许访问者访问
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
6. 场景类

public class Client {
	public static void main(String[] args) {
		for(Employee emp:mockEmployee()){
			emp.accept(new Visitor());
		}
	}
	//模拟出公司的人员情况,我们可以想象这个数据是通过持久层传递过来的
	public static List<Employee> mockEmployee(){
		List<Employee> empList = new ArrayList<Employee>();
		//产生张三这个员工
		CommonEmployee zhangSan = new CommonEmployee();
		zhangSan.setJob("编写Java程序,绝对的蓝领、苦工加搬运工");
		zhangSan.setName("张三");
		zhangSan.setSalary(1800);
		zhangSan.setSex(Employee.MALE);
		empList.add(zhangSan);
		//产生李四这个员工
		CommonEmployee liSi = new CommonEmployee();
		liSi.setJob("页面美工、审美素质太不流行了");
		liSi.setName("李四");
		liSi.setSalary(1900);
		liSi.setSex(Employee.FEMALE);
		empList.add(liSi);
		//再产生一个经理
		Manager wangWu = new Manager();
		wangWu.setName("王五");
		wangWu.setPerformance("基本上是负值,但是我会拍马屁呀");
		wangWu.setSalary(18750);
		wangWu.setSex(Employee.MALE);
		empList.add(wangWu);
		return empList;
	}
}
二、访问者模式的定义

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

1. 抽象元素

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

public class ConcreteElement1 extends Element{
	//完善业务逻辑
	public void doSomething() {
		//业务处理
	}
	//允许那个访问者访问
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
&

public class ConcreteElement2 extends Element{
	//完善业务逻辑
	public void doSomething() {
		//业务处理
	}
	//允许那个访问者访问
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}
}
3. 抽象访问者

public interface IVisitor {
	//可以访问哪些对象
	public void visit(ConcreteElement1 el1);
	public void visit(ConcreteElement2 el2);
}
4. 具体访问者

public class Visitor implements IVisitor{
	//访问el1元素
	public void visit(ConcreteElement1 el1) {
		el1.doSomething();
	}
	//访问el2元素
	public void visit(ConcreteElement2 el2) {
		el2.doSomething();
	}
}
5. 结构对象

public class ObjectStruture {
	//对象生成器,这里通过一个工厂方法模式模拟
	public static Element createElement(){
		Random rand = new Random();
		if(rand.nextInt(100)>50){
			return new ConcreteElement1();
		}else{
			return new ConcreteElement2();
		}
	}
}
6. 场景类

public class Client {
	public static void main(String[] args) {
		for(int i = 0;i < 10;i++){
			//获得元素对象
			Element el = ObjectStruture.createElement();
			//接受访问者访问
			el.accept(new Visitor());
		}
	}
}
三、访问者模式的应用

1. 优点

符合单一职责原则:具体元素角色也就是Employee抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个不同的职责非常明确地分离开来。

优秀的扩展性:由于职责分开,继续增加对数据的操作非常快捷,如,现在要增加一份给大老板的报表,这份报表格式又有所不同,直接在Visitor中增加一个方法,传递数据后进行整理打印。

2. 缺点

具体元素对访问者公布细节:访问者要访问一个类就必然要求这个类公布一些方法和数据,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的。

具体元素变更比较困难:具体元素角色的增加、删除、修改都是比较困难的,就上面那个例子,要是想增加一个成员变量,如年龄age,Visitor就需要修改,如果Visitor是一个还好办,多个就很复杂了。

3. 使用场景

1)一个对象结构(List/Set/Map等)包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就是说迭代器模式已经不能胜任的情景。

2)需要对一个对象结构(List/Set/Map等)中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值