设计模式的艺术 行为型模式之访问者模式

前言

在公司上班,一般会有兼职或全职的员工,他们都发工资,上同样的班,但是工资待遇是有区别的,财务部和人事部过来调查处理的手法也不是一样的,虽然都是一样的计算工资待遇,在软件开发中存在着这样的一种情况,我们需要处理着像员工一样的集合,集合中的具体对象是不一样的,去访问时处理的手段也不一样,软件设计模式中有这么一样设计模式可以满足上述要求,其动机就是以不同的方式去操作复杂对象结构

什么是访问者模式 Visitor Pattern

提供一个作用于某对象结构中的各元素的操作表示,它使得可以在不改变各元素结构的前提下定义作用于这些元素的新操作,访问者模式是一种对象行为型模式

访问者模式的优点

(1)、增加新的访问操作方便,使用访问者模式,增加新的访问操作就意味着增加一个新的具体访问者类,实现简单,无须修改代码,符合开闭原则

(2)、将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以提供不同的访问者访问

(3)、让用户可以不修改现有的元素类层次结构的情况下,定义作用于该层次的结构操作

访问者模式的缺点

(1)、增加新的元素类很困难,在访问者模式中,每增加一个新的元素类都意味着在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者中都将增加相应的具体操作,这就违背了开闭原则

(2)、破坏了封装,访问者模式要求访问者对象并访问并调用每一个元素对象的操作,这就意味着元素对象有时候必须暴露一些自己的内部操作和内部状态,否则无法供访问者访问

访问者模式的使用场景

(1)、当一个对象结构包含着多个类型对象,希望对这些对象实施一些依赖其具体类型的操作。在访问者中针对每一种具体的类型都提供了一个访问操作,不同类型的对象可以有不同的访问操作

(2)、需要对一个对象结构中的对象进行很多不同的操作并且不相关的操作,而且需要避免让这些操作污染这些对象的类,也不希望在增加新操作时修改这些类,访问者模式将相关的访问操作集中起来定义在访问者类中,对象结构可以被不同的访问者类所使用,将对象本身的访问操作分离

(3)、对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作

访问者模式的具体实现

目录结构

员工抽象类

//员工类:抽象元素类
public interface Employee {
    public void accept(Department handler);   //接受一个抽象访问者访问
}

具体员工类

//全职员工类:具体元素类
public class FulltimeEmployee implements Employee {
    private String name; //员工姓名
    private  double weeklyWage;  //员工周薪
    private int weekTime;  //工作时间
    @Override
    public void accept(Department handler) {
        handler.visit(this);   //调用访问者的访问方法
    }

    public FulltimeEmployee(String name, double weeklyWage, int weekTime) {
        this.name = name;
        this.weeklyWage = weeklyWage;
        this.weekTime = weekTime;
    }

    public String getName() {
        return name;
    }

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

    public double getWeeklyWage() {
        return weeklyWage;
    }

    public void setWeeklyWage(double weeklyWage) {
        this.weeklyWage = weeklyWage;
    }

    public int getWeekTime() {
        return weekTime;
    }

    public void setWeekTime(int weekTime) {
        this.weekTime = weekTime;
    }
}
public class ParttimeEmployee implements  Employee {
    private String name ;  //员工姓名
    private double hourWage; //员工时薪
    private int workTime; //工作时间

    public ParttimeEmployee(String name, double hourWage, int workTime) {
        this.name = name;
        this.hourWage = hourWage;
        this.workTime = workTime;
    }

    public String getName() {
        return name;
    }

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

    public double getHourWage() {
        return hourWage;
    }

    public void setHourWage(double hourWage) {
        this.hourWage = hourWage;
    }

    public int getWorkTime() {
        return workTime;
    }

    public void setWorkTime(int workTime) {
        this.workTime = workTime;
    }

    @Override
    public void accept(Department handler) {
        handler.visit(this);  //调用访问者访问的方法
    }
}

抽象部门类

//部门类:抽象访问者类,
public abstract class Department {
    //声明一组重载的访问方法,用于访问不同类型的具体元素
    public abstract void visit(FulltimeEmployee employee);
    public abstract void visit(ParttimeEmployee employee);
}

具体访问者类

//财务部类:具体访问者类
public class FADepartment extends  Department {
    @Override
    //实现财务部对全职员工的访问
    public void visit(FulltimeEmployee employee) {
    int workTime=employee.getWeekTime();
    double weekWage=employee.getWeeklyWage();
    if(workTime>40){
        weekWage=weekWage+(workTime-40)*100;
    }else if(workTime<40){
        weekWage=weekWage-(40-workTime)*80;
        if(weekWage<0){
            weekWage=0;
        }
    }
    System.out.println("正式员工"+employee.getName()+"实际工资为"+weekWage+"元");
    }

    @Override
    //实现财务部对兼职员工的访问
    public void visit(ParttimeEmployee employee) {
        int workTime=employee.getWorkTime();
        double hourWage=employee.getHourWage();
        System.out.println("临时工"+employee.getName()+"实际工资为"+workTime*hourWage+"元");
    }
}
//人力资源部类:具体访问者类
public class HRDepartment extends  Department {
    //实现人力资源部对全员的访问
    @Override
    public void visit(FulltimeEmployee employee) {
        int workTime=employee.getWeekTime();
        System.out.println("正式员工"+employee.getName()+"实际工作时间为"+workTime+"小时");
        if(workTime>40){
            System.out.println("正式员工"+employee.getName()+"加班时间为"+(workTime-40)+"小时");
        }else  if(workTime<40){
            System.out.println("正式员工"+employee.getName()+"请假时间为"+(40-workTime)+"小时");
        }
    }
    //实现人力资源对兼职员工的访问
    @Override
    public void visit(ParttimeEmployee employee) {
            int workTime=employee.getWorkTime();
            System.out.println("临时工"+employee.getName()+"实际工作时间为"+workTime+"小时");
    }
}

员工列表类

//员工列表类:对象结构
public class EmployeeList {
    //定义了一个集合用于存储员工对象
    private ArrayList<Employee> list=new ArrayList<Employee>();

    public void addEmployee(Employee employee){
        list.add(employee);
    }
    //遍历访问员工集合中的每一个员工对象
    public void accept(Department handler){
        for(Object object:list){
            ((Employee)object).accept(handler);
        }
    }
}

辅助工具类

public class XMLUtil {
    //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
    public static Object getBean() {
        try {
            //创建文档对象
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document document = builder.parse(XMLUtil.class.getClassLoader().getResource("").getPath() + new File("cfg.xml"));

            //获取包含类名的文本节点
            NodeList list = document.getElementsByTagName("className");
            Node node = list.item(0).getFirstChild();
            String className = node.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c = Class.forName(className);
            Object object = c.newInstance();
            return object;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<config>
    <className>com.company.FADepartment</className>
</config>

客户端测试类

public class Main {

    public static void main(String[] args) {
        EmployeeList list = new EmployeeList();
        Employee fte1, fte2, fte3, pte1, pte2;
        fte1 = new FulltimeEmployee("张无忌", 3200.00, 23);
        fte2 = new FulltimeEmployee("杨过", 234213.3, 324);
        fte3 = new FulltimeEmployee("段誉", 2400, 23);
        pte1 = new FulltimeEmployee("洪七公", 80, 20);
        pte2 = new FulltimeEmployee("郭靖", 60.0, 43);

        list.addEmployee(fte1);
        list.addEmployee(fte2);
        list.addEmployee(fte3);
        list.addEmployee(pte1);
        list.addEmployee(pte2);

        Department dep;
        dep=(Department) XMLUtil.getBean();
        list.accept(dep);
    }
}

转载请注明出处,掌声送给社会人

猜你喜欢

转载自blog.csdn.net/SCDN_CP/article/details/83414080
今日推荐