Java使用访问者模式解决公司层级结构图问题详解

 更新时间:2018年04月24日 11:00:03   转载 作者:chengqiuming  
这篇文章主要介绍了Java使用访问者模式解决公司层级结构图问题,结合实例形式分析了访问者模式的概念、原理及Java使用访问者模式解决公司曾经结构图问题的相关操作技巧与注意事项,需要的朋友可以参考下

本文实例讲述了Java使用访问者模式解决公司层级结构图问题。分享给大家供大家参考,具体如下:

一. 模式定义

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

二. 模式举例

1 模式分析

我们借用公司层级结构来说明这一模式。

2 访问者模式静态类图

3 代码示例

3.1 抽象员工一Staff

package com.demo.structure;
import com.demo.visitor.IVisitor;
/**
 * 抽象员工类
 *
 * @author
 *
 */
public abstract class Staff {
  // 员工号
  protected String no;
  // 职工名字
  protected String name;
  // 职位
  protected String position;
  // 薪资
  protected float salary;
  // 私有属性 长度字符串
  private int length;
  // 构造方法
  public Staff(String no, String name, String position, float salary) {
    this.no = no;
    this.name = name;
    this.position = position;
    this.salary = salary;
    // 计算总字节长度
    this.length += (no == null || "".equals(no.trim())) ? 0
        : no.getBytes().length;
    this.length += (name == null || "".equals(name.trim())) ? 0 : name
        .getBytes().length;
    this.length += (position == null || "".equals(position.trim())) ? 0
        : position.getBytes().length;
    this.length += String.valueOf(salary).getBytes().length;
  }
  // 获得用户基本信息
  public void printUserBaseInfo() {
    System.out.println("-|" + this.no + " " + this.name + " "
        + this.position + " " + this.salary);
  }
  // 添加员工信息
  public abstract void add(Staff staff);
  // 删除员工
  public abstract Staff remove(String no);
  // 接收访问者对象
  public abstract void accept(IVisitor visitor);
  public String getNo() {
    return no;
  }
  public void setNo(String no) {
    this.no = no;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getPosition() {
    return position;
  }
  public void setPosition(String position) {
    this.position = position;
  }
  public float getSalary() {
    return salary;
  }
  public void setSalary(float salary) {
    this.salary = salary;
  }
}

3.2 管理者一Manager

package com.demo.structure;
import java.util.ArrayList;
import com.demo.visitor.IVisitor;
/**
 * 管理人员(手下有其他员工的人)
 *
 * @author
 *
 */
public class Manager extends Staff {
  // 存储手下员工信息
  private final ArrayList<Staff> arrayList = new ArrayList<Staff>();
  // 构造方法
  public Manager(String no, String name, String position, float salary) {
    super(no, name, position, salary);
  }
  /**
   * 增加一个员工
   */
  @Override
  public void add(Staff staff) {
    this.arrayList.add(staff);
  }
  /**
   * 删除员工信息
   */
  @Override
  public Staff remove(String no) {
    Staff staff = null;
    if (no != null && !"".equals(no.trim())) {
      for (int i = 0; i < this.arrayList.size(); i++) {
        if (this.arrayList.get(i) == null) {
          continue;
        }
        if (no.equals(this.arrayList.get(i).getNo())) {
          staff = this.arrayList.remove(i);
          break;
        }
      }
    }
    return staff;
  }
  // 接收访问者对象
  @Override
  public void accept(IVisitor visitor) {
    // 访问自身
    visitor.visit(this);
    // 遍历list列表中的各个元素对象,接收访问者对象
    for (int i = 0; i < this.arrayList.size(); i++) {
      if (this.arrayList.get(i) == null) {
        continue;
      }
      // 接收访问者对象
      this.arrayList.get(i).accept(visitor);
    }
  }
}

3.3 普通员工一Employees

package com.demo.structure;
import com.demo.visitor.IVisitor;
/**
 * 普通员工(真正干活的人)
 *
 * @author
 *
 */
public class Employees extends Staff
{
  // 构造方法
  public Employees(String no, String name, String position, float salary)
  {
    super(no, name, position, salary);
  }
  /**
   * 添加员工信息
   */
  @Override
  public void add(Staff staff)
  {
    return;
  }
  /**
   * 删除员工信息
   */
  @Override
  public Staff remove(String no)
  {
    // 直接返回null
    return null;
  }
  // 接收访问者对象
  public void accept(IVisitor visitor)
  {
    visitor.visit(this);
  }
}

3.4 访问者接口一IVisitor

package com.demo.visitor;
import com.demo.structure.Employees;
import com.demo.structure.Manager;
/**
 * 访问者接口
 *
 * @author
 *
 */
public interface IVisitor {
  // 访问管理者
  public void visit(Manager manager);
  // 访问普通员工
  public void visit(Employees employees);
}

3.5 员工基本信息访问者一PrintBaseInfoVistor

package com.demo.visitor;
import com.demo.structure.Employees;
import com.demo.structure.Manager;
/**
 * 打印基本信息访问者
 *
 * @author
 *
 */
public class PrintBaseInfoVisitor implements IVisitor {
  /**
   * 访问管理者对象
   */
  public void visit(Manager manager) {
    System.out.print("- 管理者:");
    manager.printUserBaseInfo();
  }
  /**
   * 访问普通员工对象
   */
  public void visit(Employees employees) {
    System.out.print("- 一般员工:");
    employees.printUserBaseInfo();
  }
}

3.6 创建统计员工薪资的访问者接口一ISalaryVistor

package com.demo.visitor;
/**
 * 计算薪资访问者
 *
 * @author
 *
 */
public interface ISalaryVisitor extends IVisitor {
  // 统计管理者薪资情况
  public void printManagerTotalSalary();
  // 统计一般员工薪资情况
  public void printEmployeesTotalSalary();
  // 统计所有员工薪资情况
  public void printTotalSalary();
}

3.7 统计员工薪资访问者实现一SalaryVistor

package com.demo.visitor;
import com.demo.structure.Employees;
import com.demo.structure.Manager;
/**
 * 计算薪资访问者具体实现
 *
 * @author
 *
 */
public class SalaryVisitor implements ISalaryVisitor {
  // 管理者薪资总和
  private float managerSalary;
  // 普通员工薪资总和
  private float employeesSalary;
  public SalaryVisitor() {
    managerSalary = 0;
    employeesSalary = 0;
  }
  // 访问管理者
  public void visit(Manager manager) {
    managerSalary += manager.getSalary();
  }
  // 访问普通员工
  public void visit(Employees employees) {
    employeesSalary += employees.getSalary();
  }
  // 统计一般员工薪资情况
  public void printEmployeesTotalSalary() {
    System.out.println("一般员工薪资总和:" + employeesSalary);
  }
  // 统计管理者薪资情况
  public void printManagerTotalSalary() {
    System.out.println("管理者薪资总和:" + managerSalary);
  }
  // 统计所有员工薪资情况
  public void printTotalSalary() {
    System.out.println("员工薪资总和:" + (managerSalary + employeesSalary));
  }
}

3.8 客户端测试一Client

package com.demo;
import com.demo.structure.Employees;
import com.demo.structure.Manager;
import com.demo.structure.Staff;
import com.demo.visitor.PrintBaseInfoVisitor;
import com.demo.visitor.SalaryVisitor;
/**
 * 主应用程序
 *
 * @author
 *
 */
public class Client {
  /**
   * @param args
   */
  public static void main(String[] args) {
    // 公司CEO
    Staff boss = new Manager("1", "大老板", "CEO", 100000);
    /**
     * CEO手下有若干部门经理
     */
    // 财务部经理
    Staff financeManager = new Manager("11", "张总", "财务部经理", 60000);
    // 人事部经理
    Staff personnelManager = new Manager("12", "王总", "人事部经理", 60000);
    // 技术部经理
    Staff technicalManager = new Manager("13", "陈总", "技术部经理", 60000);
    /**
     * 技术部门还有助理和若干主管
     */
    // 技术部门助理
    Staff deptAssistant = new Manager("1301", "王助理", "部门助理", 20000);
    // 技术部门主管1
    Staff deptManager1 = new Manager("1302", "主管1", "技术主管", 30000);
    /**
     * 技术主管deptManager1 下面还有软件工程师(最终干活的人)
     */
    Staff softwareEngineer1 = new Employees("1302001", "张三", "软件工程师", 5000);
    Staff softwareEngineer2 = new Employees("1302002", "李四", "软件工程师", 5500);
    Staff softwareEngineer3 = new Employees("1302003", "王五", "软件工程师", 4500);
    // 为技术主管1添加员工信息
    deptManager1.add(softwareEngineer1);
    deptManager1.add(softwareEngineer2);
    deptManager1.add(softwareEngineer3);
    // 技术部门主管2
    Staff deptManager2 = new Manager("1303", "主管2", "技术主管", 30000);
    // 为技术部经理 添加:部门助理、技术主管1和技术主管2
    technicalManager.add(deptAssistant);
    technicalManager.add(deptManager1);
    technicalManager.add(deptManager2);
    // 市场部经理
    Staff marketingManager = new Manager("14", "吴总", "市场部经理", 60000);
    // 为CEO 添加:财务部经理、人事部经理、技术部经理和市场部经理
    boss.add(financeManager);
    boss.add(personnelManager);
    boss.add(technicalManager);
    boss.add(marketingManager);
    // 打印CEO 信息
    // boss.printUserBaseInfo();
    // 打印CEO 手下员工信息
    boss.accept(new PrintBaseInfoVisitor());
    /**
     * 统计员工薪资情况
     */
    // 创建统计员工薪资访问者
    SalaryVisitor visitor = new SalaryVisitor();
    // 让大老板接受该访问者
    boss.accept(visitor);
    // 管理者薪资统计情况
    visitor.printManagerTotalSalary();
    // 一般员工薪资统计情况
    visitor.printEmployeesTotalSalary();
    // 所有员工薪资统计情况
    visitor.printTotalSalary();
  }
}

4 运行结果

- 管理者:-|1 大老板 CEO 100000.0
- 管理者:-|11 张总 财务部经理 60000.0
- 管理者:-|12 王总 人事部经理 60000.0
- 管理者:-|13 陈总 技术部经理 60000.0
- 管理者:-|1301 王助理 部门助理 20000.0
- 管理者:-|1302 主管1 技术主管 30000.0
- 一般员工:-|1302001 张三 软件工程师 5000.0
- 一般员工:-|1302002 李四 软件工程师 5500.0
- 一般员工:-|1302003 王五 软件工程师 4500.0
- 管理者:-|1303 主管2 技术主管 30000.0
- 管理者:-|14 吴总 市场部经理 60000.0
管理者薪资总和:420000.0
一般员工薪资总和:15000.0
员工薪资总和:435000.0

三. 该模式设计原则

1 "开-闭"原则

2 单一职责原则

四. 使用场合

1 如果在一个对象结构中包含很多不同类型的对象,它们有不同的接口,而想对这些不同对象实施一些依赖于具体类的操作。

2 需要对一个对象结构中的对象进行很多不同的并且不相关操作,而想避免让这些操作与这些对象的类关联起来。访问者模式使得可以将相关操作集中起来,单独定义在一个类中。

3 当该对象结构被很多应用共享时,用访问者模式让每个应用仅包含需要用到的操作。

4 定义对象结构的类很少改变,但经常需要在此结构中定义新的操作。

五. 访问者模式静态类图

更多java相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总

希望本文所述对大家java程序设计有所帮助。

相关文章

  • 详解Spring Boot 配置加载顺序及属性加载顺序

    详解Spring Boot 配置加载顺序及属性加载顺序

    这篇文章主要介绍了详解Spring Boot 配置加载顺序及属性加载顺序,本章内容基于 Spring Boot 2.0 进行详解,感兴趣的朋友跟随脚本之家小编一起看看吧
    2018-08-08
  • springBoot 与neo4j的简单整合示例

    springBoot 与neo4j的简单整合示例

    这篇文章主要介绍了springBoot 与neo4j的简单整合示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • java多线程之火车售票系统模拟实例

    java多线程之火车售票系统模拟实例

    下面小编就为大家带来一篇java多线程之火车售票系统模拟实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • java并发分段锁实践代码

    java并发分段锁实践代码

    这篇文章主要介绍了java并发分段锁实践代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07
  • Java Web之限制用户多处登录实例代码

    Java Web之限制用户多处登录实例代码

    本篇文章主要介绍了Java Web之限制用户多处登录实例代码,可以限制单个用户在多个终端登录。非常具有实用价值,需要的朋友可以参考下。
    2017-03-03
  • java实现文件归档和还原

    java实现文件归档和还原

    这篇文章主要为大家详细介绍了java实现文件归档和还原,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • Java8中的LocalDateTime和Date一些时间操作方法

    Java8中的LocalDateTime和Date一些时间操作方法

    这篇文章主要介绍了Java8中的LocalDateTime和Date一些时间操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • Log4j 配置日志打印时区的实现方法

    Log4j 配置日志打印时区的实现方法

    下面小编就为大家分享一篇Log4j 配置日志打印时区的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2017-12-12
  • 详解Spring Boot使用redis实现数据缓存

    详解Spring Boot使用redis实现数据缓存

    本篇文章主要介绍了详解Spring Boot使用redis实现数据缓存,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • 详解Java如何进行Base64的编码(Encode)与解码(Decode)

    详解Java如何进行Base64的编码(Encode)与解码(Decode)

    这篇文章主要介绍了详解Java如何进行Base64的编码(Encode)与解码(Decode),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03

最新评论