设计模式23-访问者模式

213 阅读3分钟

1.场景问题解决

1.1 场景描述

雇员管理系统遇到的问题: 需要添加一些新的操作功能

1.2 OO设计

  • oo 该package为oo用法
    • Employee 为雇员信息
    • Employees 为对每个雇员信息操作类
    • MainOOTest 为测试类
public class Employee {
	private String name;
	private float income;
	private int vacationDays;
	private int degree;

	public Employee(String name, float income, int vacationDays, int degree) {
		this.name = name;
		this.income = income;
		this.vacationDays = vacationDays;
		this.degree = degree;
	}

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

	public String getName() {
		return name;
	}

	public void setIncome(float income) {
		this.income = income;
	}

	public float getIncome() {
		return income;
	}

	public void setVacationDays(int vacationDays) {
		this.vacationDays = vacationDays;
	}

	public int getVacationDays() {
		return vacationDays;
	}

	public void setDegree(int degree) {
		this.degree = degree;
	}

	public int getDegree() {
		return degree;
	}

}

public class Employees {
	private HashMap<String, Employee> employees;

	public Employees() {
		employees = new HashMap<String, Employee>();
	}

	public void Attach(Employee employee) {
		employees.put(employee.getName(), employee);
	}

	public void Detach(Employee employee) {
		employees.remove(employee);
	}

	public Employee getEmployee(String name) {
		return employees.get(name);
	}

	public void getCompensation() {
		for (Employee employee : employees.values()) {
			System.out.println(employee.getName()+ "'s Compensation is "+ (employee.getDegree()* employee.getVacationDays() * 100));
		}
	}
}




public class MainOOTest {
	public static void main(String[] args) {
		Employees mEmployees = new Employees();
		mEmployees.Attach(new Employee("Tom", 4500, 8, 1));
		mEmployees.Attach(new Employee("Jerry", 6500, 10, 2));
		mEmployees.Attach(new Employee("Jack", 9600, 12, 3));
		mEmployees.getCompensation();
	}
}

1.3 需求变动

1.4 带来问题

2.用设计模式改进

2.1 分析

2.2 重新设计

23访问者模式-2.png

2.3 源码

  • visitor 该package 为访问者模式优化后

    • 1)Element 为元素抽象类,其中有 accept(Visitor visitor)
    • 2)Employee 为雇员信息 extends Element,实现了accept(Visitor visitor),触发将自己传给visitor.visit(this)[ 5) ];
    • 3)Employees 为对每个雇员信息操作类, 会发起调出发每个Employee.accept(visitor);
    • 4)Visitor 为一个接口 根据需要实现该接口:
    • 5)CompensationVisitor 该访问者实现了visit,并对传入的Element单独处理.
    • 6)MainOOTest 为测试类
public interface Visitor {
	abstract public void visit(Element element);
}



public abstract class Element {
	abstract public void accept(Visitor visitor);
}




public class Employee extends Element {

	private String name;
	private float income;
	private int vacationDays;
	private int degree;

	public Employee(String name, float income, int vacationDays, int degree) {
		this.name = name;
		this.income = income;
		this.vacationDays = vacationDays;
		this.degree = degree;
	}

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

	public String getName() {
		return name;
	}

	public void setIncome(float income) {
		this.income = income;
	}

	public float getIncome() {
		return income;
	}

	public void setVacationDays(int vacationDays) {
		this.vacationDays = vacationDays;
	}

	public int getVacationDays() {
		return vacationDays;
	}

	public void setDegree(int degree) {
		this.degree = degree;
	}

	public int getDegree() {
		return degree;
	}

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

}


public class Employees {
	private HashMap<String, Employee> employees;

	public Employees() {
		employees = new HashMap();
	}

	public void Attach(Employee employee) {
		employees.put(employee.getName(), employee);
	}

	public void Detach(Employee employee) {
		employees.remove(employee);
	}

	public Employee getEmployee(String name) {
		return employees.get(name);
	}

	public void accept(Visitor visitor) {
		for (Employee e : employees.values()) {
			e.accept(visitor);
		}
	}
}




public class CompensationVisitor implements Visitor {

	@Override
	public void visit(Element element) {
		Employee employee = ((Employee) element);
		System.out.println(employee.getName() + "'s Compensation is "+ (employee.getDegree() * employee.getVacationDays() * 10));
	}

}



public class MainVisitorTest {
	public static void main(String[] args) {
		Employees mEmployees = new Employees();

		mEmployees.Attach(new Employee("Tom", 4500, 8, 1));
		mEmployees.Attach(new Employee("Jerry", 6500, 10, 2));
		mEmployees.Attach(new Employee("Jack", 9600, 12, 3));

		mEmployees.accept(new CompensationVisitor());
	}
}

3.设计模式总结

3.1 定义

访问者模式:对于一组对象,在不改变数据结构的前提下,增加作用于这些结构元素新的功能。
适用于数据结构相对稳定,它把数据结构和作用于其上的操作解耦,使得操作集合可以相对自由地演化。

3.2 分析思路

23访问者模式-1.png

3.3 优缺点

  • 优点:
    符合单一职责原则
    扩展性良好
    有益于系统的管理和维护
  • 缺点:
    增加新的元素类变得很困难
    破坏封装性

4. 设计模式使用场景及注意

4.1 使用场景

  • 如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的

4.2 注意

  • 与迭代器的关系

5.参考文章

内容总计于HeadFirst设计模式及相关视频