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程序设计有所帮助。

相关文章

  • Java报错sun.misc.Unsafe.park(Native Method)问题

    Java报错sun.misc.Unsafe.park(Native Method)问题

    这篇文章主要介绍了Java报错sun.misc.Unsafe.park(Native Method)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • 基于java中反射的总结分析

    基于java中反射的总结分析

    所谓反射,就是根据一个已经实例化了的对象来还原类的完整信息
    至少对我而言,我认为它带给我的好处是,让我从下往上的又了解了一遍面向对象

    2013-05-05
  • Java的JDBC编程使用之连接Mysql数据库

    Java的JDBC编程使用之连接Mysql数据库

    这篇文章主要给大家介绍了关于Java的JDBC编程使用之连接Mysql数据库的相关资料,JDBC是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,需要的朋友可以参考下
    2023-12-12
  • xxl-job 带参数执行和高可用部署方法

    xxl-job 带参数执行和高可用部署方法

    这篇文章主要介绍了xxl-job 带参数执行和高可用部署,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Java设计模式中的装饰器模式简析

    Java设计模式中的装饰器模式简析

    这篇文章主要介绍了Java设计模式中的装饰器模式简析,装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能,通常给对象添加功能,要么直接修改对象添加相应的功能,要么派生对应的子类来扩展,抑或是使用对象组合的方式,需要的朋友可以参考下
    2023-12-12
  • MyBatis动态SQL标签用法实例详解

    MyBatis动态SQL标签用法实例详解

    本文通过实例代码给大家介绍了MyBatis动态SQL标签用法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-07-07
  • Spring 代码技巧梳理总结让你爱不释手

    Spring 代码技巧梳理总结让你爱不释手

    这篇文章主要分享了Spring 代码技巧梳理总结,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-06-06
  • Java踩坑记录之BigDecimal类

    Java踩坑记录之BigDecimal类

    这篇文章主要给大家介绍了关于Java踩坑记录之BigDecimal类的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • SpringBoot this调用@Bean效果详解

    SpringBoot this调用@Bean效果详解

    这篇文章主要介绍了在一个@Bean方法内,this调用同一个类的@Bean方法会有什么效果,我们可以通过bean的名称、bean的类型或者bean的名称+类型来获取容器中的bean
    2023-02-02
  • java中的转义字符介绍

    java中的转义字符介绍

    普通的转义字符序列和八进制转义字符都比Unicode转义字符要好得多,因为与Unicode转义字符不同,转义字符序列是在程序被解析为各种符号之后被处理的
    2013-09-09

最新评论