查看: 246|回复: 0

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

发表于 2018-5-4 08:00:02

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

一. 模式定义

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

二. 模式举例

1 模式分析

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

2 访问者模式静态类图

3 代码示例

3.1 抽象员工一Staff

  1. package com.demo.structure;
  2. import com.demo.visitor.IVisitor;
  3. /**
  4. * 抽象员工类
  5. *
  6. * @author
  7. *
  8. */
  9. public abstract class Staff {
  10. // 员工号
  11. protected String no;
  12. // 职工名字
  13. protected String name;
  14. // 职位
  15. protected String position;
  16. // 薪资
  17. protected float salary;
  18. // 私有属性 长度字符串
  19. private int length;
  20. // 构造方法
  21. public Staff(String no, String name, String position, float salary) {
  22. this.no = no;
  23. this.name = name;
  24. this.position = position;
  25. this.salary = salary;
  26. // 计算总字节长度
  27. this.length += (no == null || "".equals(no.trim())) ? 0
  28. : no.getBytes().length;
  29. this.length += (name == null || "".equals(name.trim())) ? 0 : name
  30. .getBytes().length;
  31. this.length += (position == null || "".equals(position.trim())) ? 0
  32. : position.getBytes().length;
  33. this.length += String.valueOf(salary).getBytes().length;
  34. }
  35. // 获得用户基本信息
  36. public void printUserBaseInfo() {
  37. System.out.println("-|" + this.no + " " + this.name + " "
  38. + this.position + " " + this.salary);
  39. }
  40. // 添加员工信息
  41. public abstract void add(Staff staff);
  42. // 删除员工
  43. public abstract Staff remove(String no);
  44. // 接收访问者对象
  45. public abstract void accept(IVisitor visitor);
  46. public String getNo() {
  47. return no;
  48. }
  49. public void setNo(String no) {
  50. this.no = no;
  51. }
  52. public String getName() {
  53. return name;
  54. }
  55. public void setName(String name) {
  56. this.name = name;
  57. }
  58. public String getPosition() {
  59. return position;
  60. }
  61. public void setPosition(String position) {
  62. this.position = position;
  63. }
  64. public float getSalary() {
  65. return salary;
  66. }
  67. public void setSalary(float salary) {
  68. this.salary = salary;
  69. }
  70. }
复制代码

3.2 管理者一Manager

  1. package com.demo.structure;
  2. import java.util.ArrayList;
  3. import com.demo.visitor.IVisitor;
  4. /**
  5. * 管理人员(手下有其他员工的人)
  6. *
  7. * @author
  8. *
  9. */
  10. public class Manager extends Staff {
  11. // 存储手下员工信息
  12. private final ArrayList<Staff> arrayList = new ArrayList<Staff>();
  13. // 构造方法
  14. public Manager(String no, String name, String position, float salary) {
  15. super(no, name, position, salary);
  16. }
  17. /**
  18. * 增加一个员工
  19. */
  20. @Override
  21. public void add(Staff staff) {
  22. this.arrayList.add(staff);
  23. }
  24. /**
  25. * 删除员工信息
  26. */
  27. @Override
  28. public Staff remove(String no) {
  29. Staff staff = null;
  30. if (no != null && !"".equals(no.trim())) {
  31. for (int i = 0; i < this.arrayList.size(); i++) {
  32. if (this.arrayList.get(i) == null) {
  33. continue;
  34. }
  35. if (no.equals(this.arrayList.get(i).getNo())) {
  36. staff = this.arrayList.remove(i);
  37. break;
  38. }
  39. }
  40. }
  41. return staff;
  42. }
  43. // 接收访问者对象
  44. @Override
  45. public void accept(IVisitor visitor) {
  46. // 访问自身
  47. visitor.visit(this);
  48. // 遍历list列表中的各个元素对象,接收访问者对象
  49. for (int i = 0; i < this.arrayList.size(); i++) {
  50. if (this.arrayList.get(i) == null) {
  51. continue;
  52. }
  53. // 接收访问者对象
  54. this.arrayList.get(i).accept(visitor);
  55. }
  56. }
  57. }
复制代码

3.3 普通员工一Employees

  1. package com.demo.structure;
  2. import com.demo.visitor.IVisitor;
  3. /**
  4. * 普通员工(真正干活的人)
  5. *
  6. * @author
  7. *
  8. */
  9. public class Employees extends Staff
  10. {
  11. // 构造方法
  12. public Employees(String no, String name, String position, float salary)
  13. {
  14. super(no, name, position, salary);
  15. }
  16. /**
  17. * 添加员工信息
  18. */
  19. @Override
  20. public void add(Staff staff)
  21. {
  22. return;
  23. }
  24. /**
  25. * 删除员工信息
  26. */
  27. @Override
  28. public Staff remove(String no)
  29. {
  30. // 直接返回null
  31. return null;
  32. }
  33. // 接收访问者对象
  34. public void accept(IVisitor visitor)
  35. {
  36. visitor.visit(this);
  37. }
  38. }
复制代码

3.4 访问者接口一IVisitor

  1. package com.demo.visitor;
  2. import com.demo.structure.Employees;
  3. import com.demo.structure.Manager;
  4. /**
  5. * 访问者接口
  6. *
  7. * @author
  8. *
  9. */
  10. public interface IVisitor {
  11. // 访问管理者
  12. public void visit(Manager manager);
  13. // 访问普通员工
  14. public void visit(Employees employees);
  15. }
复制代码

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

  1. package com.demo.visitor;
  2. import com.demo.structure.Employees;
  3. import com.demo.structure.Manager;
  4. /**
  5. * 打印基本信息访问者
  6. *
  7. * @author
  8. *
  9. */
  10. public class PrintBaseInfoVisitor implements IVisitor {
  11. /**
  12. * 访问管理者对象
  13. */
  14. public void visit(Manager manager) {
  15. System.out.print("- 管理者:");
  16. manager.printUserBaseInfo();
  17. }
  18. /**
  19. * 访问普通员工对象
  20. */
  21. public void visit(Employees employees) {
  22. System.out.print("- 一般员工:");
  23. employees.printUserBaseInfo();
  24. }
  25. }
复制代码

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

  1. package com.demo.visitor;
  2. /**
  3. * 计算薪资访问者
  4. *
  5. * @author
  6. *
  7. */
  8. public interface ISalaryVisitor extends IVisitor {
  9. // 统计管理者薪资情况
  10. public void printManagerTotalSalary();
  11. // 统计一般员工薪资情况
  12. public void printEmployeesTotalSalary();
  13. // 统计所有员工薪资情况
  14. public void printTotalSalary();
  15. }
复制代码

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

  1. package com.demo.visitor;
  2. import com.demo.structure.Employees;
  3. import com.demo.structure.Manager;
  4. /**
  5. * 计算薪资访问者具体实现
  6. *
  7. * @author
  8. *
  9. */
  10. public class SalaryVisitor implements ISalaryVisitor {
  11. // 管理者薪资总和
  12. private float managerSalary;
  13. // 普通员工薪资总和
  14. private float employeesSalary;
  15. public SalaryVisitor() {
  16. managerSalary = 0;
  17. employeesSalary = 0;
  18. }
  19. // 访问管理者
  20. public void visit(Manager manager) {
  21. managerSalary += manager.getSalary();
  22. }
  23. // 访问普通员工
  24. public void visit(Employees employees) {
  25. employeesSalary += employees.getSalary();
  26. }
  27. // 统计一般员工薪资情况
  28. public void printEmployeesTotalSalary() {
  29. System.out.println("一般员工薪资总和:" + employeesSalary);
  30. }
  31. // 统计管理者薪资情况
  32. public void printManagerTotalSalary() {
  33. System.out.println("管理者薪资总和:" + managerSalary);
  34. }
  35. // 统计所有员工薪资情况
  36. public void printTotalSalary() {
  37. System.out.println("员工薪资总和:" + (managerSalary + employeesSalary));
  38. }
  39. }
复制代码

3.8 客户端测试一Client

  1. package com.demo;
  2. import com.demo.structure.Employees;
  3. import com.demo.structure.Manager;
  4. import com.demo.structure.Staff;
  5. import com.demo.visitor.PrintBaseInfoVisitor;
  6. import com.demo.visitor.SalaryVisitor;
  7. /**
  8. * 主应用程序
  9. *
  10. * @author
  11. *
  12. */
  13. public class Client {
  14. /**
  15. * @param args
  16. */
  17. public static void main(String[] args) {
  18. // 公司CEO
  19. Staff boss = new Manager("1", "大老板", "CEO", 100000);
  20. /**
  21. * CEO手下有若干部门经理
  22. */
  23. // 财务部经理
  24. Staff financeManager = new Manager("11", "张总", "财务部经理", 60000);
  25. // 人事部经理
  26. Staff personnelManager = new Manager("12", "王总", "人事部经理", 60000);
  27. // 技术部经理
  28. Staff technicalManager = new Manager("13", "陈总", "技术部经理", 60000);
  29. /**
  30. * 技术部门还有助理和若干主管
  31. */
  32. // 技术部门助理
  33. Staff deptAssistant = new Manager("1301", "王助理", "部门助理", 20000);
  34. // 技术部门主管1
  35. Staff deptManager1 = new Manager("1302", "主管1", "技术主管", 30000);
  36. /**
  37. * 技术主管deptManager1 下面还有软件工程师(最终干活的人)
  38. */
  39. Staff softwareEngineer1 = new Employees("1302001", "张三", "软件工程师", 5000);
  40. Staff softwareEngineer2 = new Employees("1302002", "李四", "软件工程师", 5500);
  41. Staff softwareEngineer3 = new Employees("1302003", "王五", "软件工程师", 4500);
  42. // 为技术主管1添加员工信息
  43. deptManager1.add(softwareEngineer1);
  44. deptManager1.add(softwareEngineer2);
  45. deptManager1.add(softwareEngineer3);
  46. // 技术部门主管2
  47. Staff deptManager2 = new Manager("1303", "主管2", "技术主管", 30000);
  48. // 为技术部经理 添加:部门助理、技术主管1和技术主管2
  49. technicalManager.add(deptAssistant);
  50. technicalManager.add(deptManager1);
  51. technicalManager.add(deptManager2);
  52. // 市场部经理
  53. Staff marketingManager = new Manager("14", "吴总", "市场部经理", 60000);
  54. // 为CEO 添加:财务部经理、人事部经理、技术部经理和市场部经理
  55. boss.add(financeManager);
  56. boss.add(personnelManager);
  57. boss.add(technicalManager);
  58. boss.add(marketingManager);
  59. // 打印CEO 信息
  60. // boss.printUserBaseInfo();
  61. // 打印CEO 手下员工信息
  62. boss.accept(new PrintBaseInfoVisitor());
  63. /**
  64. * 统计员工薪资情况
  65. */
  66. // 创建统计员工薪资访问者
  67. SalaryVisitor visitor = new SalaryVisitor();
  68. // 让大老板接受该访问者
  69. boss.accept(visitor);
  70. // 管理者薪资统计情况
  71. visitor.printManagerTotalSalary();
  72. // 一般员工薪资统计情况
  73. visitor.printEmployeesTotalSalary();
  74. // 所有员工薪资统计情况
  75. visitor.printTotalSalary();
  76. }
  77. }
复制代码

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



回复

使用道具 举报