根据加班时长裁员, 参观者模式(Visitor Pattern)来讨论

目的

为一组各种数据提供同一个维度的访问方法

例子代码

最近360裁员又是一波新闻, 其实近年来互联网公司裁员也是司空见惯了, 感觉应该是经济大环境不好加上互联网越来越冷静了, 感觉上除了头条和拼多多还能逆势扩招, 其他大厂明里暗里裁员, 最好的也就还有少量招聘名额…

在这种情况下, 比如我们要统计加班时长裁员, 交到我们手里可能会这么写:

先定义一个员工类:

@Data
public abstract class Employee {
    //工作时长
    protected Integer workingHours;
    //薪水
    protected BigDecimal salary;
}

然后定义三种员工:

程序员:

@Data
public class Coder extends Employee {
    //加班时长
    private Integer overtimeHours;

    public Coder(Integer workingHours, BigDecimal salary, Integer overtimeHours) {
        this.workingHours = workingHours;
        this.salary = salary;
        this.overtimeHours = overtimeHours;
    }
}

人力资源:

@Data
public class Hr extends Employee {
    private Integer resumeCount;

    public Hr(Integer workingHours, BigDecimal salary, Integer resumeCount) {
        this.workingHours = workingHours;
        this.salary = salary;
        this.resumeCount = resumeCount;
    }
}

销售人员:

public class Salesman extends Employee {
    public Salesman(Integer workingHours, BigDecimal salary) {
        this.workingHours = workingHours;
        this.salary = salary;
    }
}

程序员呢, 工作时间是根据正常上班时间+加班时间算的, hr 是是需要加加上每个简历处理二个小时, 销售人员呢, 需要根据实际情况加随机的 8 个小时

public static void main(String[] args) {
    Integer totalWorkHours = 0;
    for (Employee employee : EMPLOYEE_LIST) {
        if (employee instanceof Coder) {
            totalWorkHours += employee.getWorkingHours() + ((Coder) employee).getOvertimeHours();
        }
        if (employee instanceof Hr) {
            totalWorkHours += employee.getWorkingHours() + ((Hr) employee).getResumeCount()*2;
        }
        totalWorkHours += employee.getWorkingHours() + new Random().nextInt(8);
    }
    System.out.println("总时长: " + totalWorkHours);
}

然后我们使用这个方法计算员工实际工作时间, 就可以输出固定的结果了

问题分析

这个里面有几个问题, 一个是计算员工耗时的方法, 如果新增一种员工类型, 需要再加个 if-else

另外是这个规则可能经常需要变化, 当前是汇报给老板的工时的规则, 比如对外公布的一套规则可能是程序员的工时需要取一半, hr 保持原样, 销售减 2 个小时完

还有可能维度有变化, 比如要统计平均工资, 这些规则如果不是可替换的, 模式客户端直接来访问这种数据结构进行操作, 需求变化, 客户端会很痛苦.

参观者模式

先定义一个参观者类:

public interface ElementVisitor<R, E, P> {
    R visit(E e, P p);
}

定义一个元素类:

public interface Element<R, P> {
    R accept(ElementVisitor<R, Element, P> v, P p);
}

员工类改成如下:

@Data
public abstract class Employee implements Element<Integer,Integer> {
    //默认工作时长,比如 8 小时
    protected Integer workingHours;
    //每小时薪水
    protected BigDecimal salary;

    @Override
    public Integer accept(ElementVisitor<Integer, Element, Integer> v, Integer param) {
        return v.visit(this, param);
    }
}

定义三个参观者的泛型屏蔽接口:

public interface RealTimeEmployeeVisitor 
                                extends ElementVisitor<Integer, Employee, Void> {
}

依次定义三个具体的参观者:

程序员:

public class CoderVisitor implements RealTimeEmployeeVisitor {

    @Override
    public Integer visit(Employee coder, Void param) {
        if (coder instanceof Coder) {
            return coder.getWorkingHours() + ((Coder) coder).getOvertimeHours();
        }
        return 0;
    }
}

hr:

public class HrVisitor implements RealTimeEmployeeVisitor {
    @Override
    public Integer visit(Employee hr, Void param) {
        if (hr instanceof Hr) {
            return hr.getWorkingHours() + ((Hr) hr).getResumeCount() * 2;
        }
        return 0;
    }
}

销售人员:

public class SalesmanVisitor implements RealTimeEmployeeVisitor {
    @Override
    public Integer visit(Salesman e, Integer param) {
        return e.getWorkingHours() + param;
    }
}

使用方式:

public static void main(String[] args) {
    Map<Class,ElementVisitor> vistorMap = new HashMap<>();
    vistorMap.put(Coder.class,new CoderVisitor());
    vistorMap.put(Hr.class,new HrVisitor());
    vistorMap.put(Salesman.class,new SalesmanVisitor());

    Integer totalWorkHours = 0;
    for (Employee employee : EMPLOYEE_LIST) {
        totalWorkHours += employee.accept(vistorMap.get(employee.getClass()),null);
    }
    System.out.println("工作总时长: " + totalWorkHours);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Qb8vBDB-1602244248681)(/assets/import.png)]

课后作业

  1. 完成缺点中的第二个规则的替换
  2. 根据 salary 字段计算员工总薪水, 程序员按正常工作时长算, hr 按简历处理时长算, 销售人员按总时长算
  3. 微信原文:
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值