小明公司的福利
小明作为一个程序员,难免不经常加班,所以他这一年的年假也没有机会享受,但是小明的公司福利很好,对于公司没有休年假的员工作相应的补偿
具体的补偿根据员工的入职时间和职级来的,我们先看看小明公司的员工
public class Staff {
String name;
int workYear;
int level;
int vacationDay;
public Staff(String name, int workYear, int level, int vacationDay) {
this.name = name;
this.workYear = workYear;
this.level = level;
this.vacationDay = vacationDay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWorkYear() {
return workYear;
}
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getVacationDay() {
return vacationDay;
}
public void setVacationDay(int vacationDay) {
this.vacationDay = vacationDay;
}
}
员工集合类
public class Staffs {
Map<String, Staff> staffMap = new HashMap<>(20);
public Staffs() {
Staff xiaoming = new Staff("xiaoming", 2, 1, 5);
Staff zhuguan = new Staff("zhuguan", 4, 2, 4);
Staff jingli = new Staff("jingli", 5, 4, 1);
staffMap.put(xiaoming.getName(), xiaoming);
staffMap.put(zhuguan.getName(), zhuguan);
staffMap.put(jingli.getName(), jingli);
}
}
现在我们要开始补偿员工了,规则是:年限的系数为1,职级的系数也为1,然后乘以每天50元的补偿。比如小明,如果还有1天没休,那么他这一天应该得到的补偿为:(1x2+1x1)x50,就是一天150块钱的补偿,所以对于小明来说,他还有5天的年假,所以他能得到750元的补偿。那么这个功能怎么加呢?由于是小明负责这个程序,他在员工集合类中加入了一个方法:
public class Staffs {
Map<String, Staff> staffMap = new HashMap<>(20);
public Staffs() {
Staff xiaoming = new Staff("xiaoming", 2, 1, 5);
Staff zhuguan = new Staff("zhuguan", 4, 2, 4);
Staff jingli = new Staff("jingli", 5, 4, 1);
staffMap.put(xiaoming.getName(), xiaoming);
staffMap.put(zhuguan.getName(), zhuguan);
staffMap.put(jingli.getName(), jingli);
}
void printCompensation() {
for (Staff staff : staffMap.values()) {
System.out.println(staff.getName() + " 应该得到" + ((staff.getWorkYear() + staff.getLevel()) * 50 * staff.getVacationDay()) + "元补偿");
}
}
}
得到的结果:
xiaoming 应该得到750元补偿
jingli 应该得到450元补偿
zhuguan 应该得到1200元补偿
小明开开心心的去找主管交代码准备领钱了,主管看了小明的代码说,你这样做违背了开闭原则。主管接着说,在没有这个福利之前,我们的员工类和员工集合类一直都没有任何的修改,而因为这个福利,加入了一个新的方法,这不是最关键的,关键是,如果明年没有这个福利了或者这个福利的补偿算法变了,你又必须修改员工集合类(Staffs),所以对于福利这一块,它是变动的。小明着急的问,那怎么办呢,主管说,对于这种结构比较固定的类,如果我们需要利用他们的元素去做一些其他事情,并且这些事情是变化的,我们需要将它独立出来,这次我们需要的是访问者模式
可被访问者接口:
public interface Visitable {
void accept(Visitor visitor);
}
我们的员工实现我们的Visitable接口:
public class Staff implements Visitable {
String name;
int workYear;
int level;
int vacationDay;
public Staff(String name, int workYear, int level, int vacationDay) {
this.name = name;
this.workYear = workYear;
this.level = level;
this.vacationDay = vacationDay;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getWorkYear() {
return workYear;
}
public void setWorkYear(int workYear) {
this.workYear = workYear;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public int getVacationDay() {
return vacationDay;
}
public void setVacationDay(int vacationDay) {
this.vacationDay = vacationDay;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
增加一个访问者接口:
public interface Visitor {
void visit(Staff staff);
}
实现一个具体的访问者,比如我们的计算补偿的访问者:
public class CompensationVisit implements Visitor {
@Override
public void visit(Staff staff) {
System.out.println(staff.getName() + " 应该得到" + ((staff.getWorkYear() + staff.getLevel()) * 50 * staff.getVacationDay()) + "元补偿");
}
}
使用我们的模式来计算大家的补偿
public class Client {
public static void main(String[] args) {
CompensationVisit compensationVisit = new CompensationVisit();
Staffs staffs = new Staffs();
for (Staff staff : staffs.staffMap.values()) {
staff.accept(compensationVisit);
}
}
}
执行结果是和上面一样的:
xiaoming 应该得到750元补偿
jingli 应该得到450元补偿
zhuguan 应该得到1200元补偿
如果明年我们的福利算法变了,我们只需要在Staff的accept方法中传入另一个不同实现的访问者即可,这就是我们的访问者模式
定义
封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
角色
- 抽象元素类
- 元素类
- 抽象访问者
- 访问者
- 结构对象
访问者模式的适用场景
假如一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去
假如一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去