Java访问者模式实现优雅的对象结构处理

Java访问者模式实现优雅的对象结构处理

什么是访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,它可以用于在不改变对象结构的前提下,对对象的元素进行新的操作。它将算法与对象结构分离开来,能够在不修改已有的类结构的情况下,向现有对象结构添加新的操作。

访问者模式的角色

访问者模式中包含如下角色:

  • 抽象访问者(Visitor):为对象结构中每一个具体元素类ConcreteElement声明一个访问操作,从这个操作的名称或参数类型可以清楚知道它属于哪个具体的元素类。抽象访问者为对象结构中的每一个具体元素类ConcreteElement都定义了一个访问操作Visit()。

  • 具体访问者(ConcreteVisitor):实现不同的访问操作,即对应不同的具体元素类ConcreteElement的访问操作。

  • 抽象元素(Element):定义一个接受访问的方法accept(),它的参数是一个访问者Visitor对象。

  • 具体元素(ConcreteElement):实现抽象元素提供的.accept()方法,其方法参数是具体的访问者对象。

  • 对象结构(ObjectStructure):具体元素的集合,提供一个高层接口允许访问者对象访问它的元素。

访问者模式的优点

  • 省去了修改现有代码,如若没有访问者模式,新增一个新功能,我们要在每个类里面加一个新的方法,所以代码变得不可控。
  • 将有关行为集中到访问者中,再通过多态等技术操作具体元素。使得增加新的访问操作比较容易。

访问者模式的缺点

  • 具体元素对访问者公布细节,违反了迪米特原则。
  • 具体元素变更比较困难。如果需要增加一个ConcreteElement的子类,那么就需要更改所有的Visitor的子类。

访问者模式的应用场景

  • 对象结构相对稳定,但其操作算法经常改变的场合。

Java实现访问者模式的示例

下面我们来看一个实现Java访问者模式的示例,假设我们有一个对象结构:一个学校,包括了不同的部门、学院、教师、学生等元素。现在我们需要对每个元素进行不同的操作,如打印信息、计算工资等。为了避免每个元素拥有不同的接口,我们可以使用访问者模式。

1. 创建元素类

我们先来定义学校中的各种元素。这里我们定义了School、Department、Teacher和Student四个类。

// School.java
public class School implements Element {
    private List<Element> elements = new ArrayList<>();

    public void add(Element element) {
        elements.add(element);
    }

    public void remove(Element element) {
        elements.remove(element);
    }

    public List<Element> getElements() {
        return elements;
    }

    @Override
    public void accept(Visitor visitor) {
        for (Element e : elements) {
            e.accept(visitor);
        }
    }
}

// Department.java
public class Department implements Element {
    private String name;
    private List<Element> elements = new ArrayList<>();

    public Department(String name) {
        this.name = name;
    }

    public void add(Element element) {
        elements.add(element);
    }

    public void remove(Element element) {
        elements.remove(element);
    }

    public List<Element> getElements() {
        return elements;
    }

    public String getName() {
        return name;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitDepartment(this);
        for (Element e : elements) {
            e.accept(visitor);
        }
    }
}

// Teacher.java
public class Teacher implements Element {
    private String name;
    private double salary;

    public Teacher(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitTeacher(this);
    }
}

// Student.java
public class Student implements Element {
    private String name;
    private String id;

    public Student(String name, String id) {
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visitStudent(this);
    }
}

2. 创建访问者接口和具体访问者

我们定义一个Visitor接口,并为每个元素实现一个visit方法,用于具体的操作。这里我们定义了PrintVisitor和SalaryVisitor两个具体访问者:

public interface Visitor {
    void visitDepartment(Department department);
    void visitTeacher(Teacher teacher);
    void visitStudent(Student student);
}

public class PrintVisitor implements Visitor {
    private String content = "";

    @Override
    public void visitDepartment(Department department) {
        content += "Department: " + department.getName() + "\n";
    }

    @Override
    public void visitTeacher(Teacher teacher) {
        content += "Teacher: " + teacher.getName() + "\n";
    }

    @Override
    public void visitStudent(Student student) {
        content += "Student: " + student.getName() + "\n";
    }

    public String getContent() {
        return content;
    }
}

public class SalaryVisitor implements Visitor {
    private double salarySum = 0;

    @Override
    public void visitDepartment(Department department) {
    }

    @Override
    public void visitTeacher(Teacher teacher) {
        salarySum += teacher.getSalary();
    }

    @Override
    public void visitStudent(Student student) {
    }

    public double getSalarySum() {
        return salarySum;
    }
}

3. 创建对象结构

我们定义一个School类作为对象结构容器,用于添加各种元素。

public class School implements Element {
    private List<Element> elements = new ArrayList<>();

    public void add(Element element) {
        elements.add(element);
    }

    public void remove(Element element) {
        elements.remove(element);
    }

    public List<Element> getElements() {
        return elements;
    }

    @Override
    public void accept(Visitor visitor) {
        for (Element e : elements) {
            e.accept(visitor);
        }
    }
}

4. 使用访问者模式进行访问

我们在调用访问对象时,只需要传入具体的访问者,对于不同的访问者,使用对应的visit函数即可完成对应操作。

public static void main(String[] args) {
    School school = new School();

    Department computerScience = new Department("Computer Science");
    Department informationManagement = new Department("Information Management");

    Teacher teacher1 = new Teacher("Jack", 8000);
    Teacher teacher2 = new Teacher("Lucy", 9000);
    Teacher teacher3 = new Teacher("Mike", 10000);

    Student student1 = new Student("Tom", "20210001");
    Student student2 = new Student("Jerry", "20210002");
    Student student3 = new Student("Alex", "20210003");

    computerScience.add(teacher1);
    computerScience.add(student1);
    computerScience.add(student2);

    informationManagement.add(teacher2);
    informationManagement.add(teacher3);
    informationManagement.add(student3);

    school.add(computerScience);
    school.add(informationManagement);

    PrintVisitor printVisitor = new PrintVisitor();
    school.accept(printVisitor);
    System.out.println(printVisitor.getContent());

    SalaryVisitor salaryVisitor = new SalaryVisitor();
    school.accept(salaryVisitor);
    System.out.println("Total salary: " + salaryVisitor.getSalarySum());
}

输出结果为:

Department: Computer Science
Teacher: Jack
Student: Tom
Student: Jerry
Department: Information Management
Teacher: Lucy
Teacher: Mike
Student: Alex
Total salary: 27000.0

本文总结

本文介绍了访问者模式的定义和角色,以及它的优缺点和使用场景。在实现方面,我们通过一个简单的学校对象结构,介绍了Java访问者模式的使用方式。访问者模式将封装变得更加灵活,能够轻松扩展对象元素的操作。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java访问者模式实现优雅的对象结构处理 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java中对象数组的使用方法详解

    以下是“Java中对象数组的使用方法详解”的完整攻略,包含了使用对象数组的方法以及相关的示例说明。 一、对象数组简介 Java中的对象数组是由一组对象组成的数组。与基本数据类型的数组不同,对象数组中存放的是引用类型的数据,如字符串、日期等。在Java中,对象数组也是一种非常常见的数据结构。 在Java中,创建对象数组需要如下的代码: // 创建Person类…

    Java 2023年5月26日
    00
  • 超全MyBatis动态代理详解(绝对干货)

    针对“超全MyBatis动态代理详解(绝对干货)”这个主题,我可以提供如下详细讲解。 MyBatis动态代理详解 什么是动态代理? 动态代理是Java中一种常见的设计模式,它通过在程序运行的时候动态创建一个实现某个接口的代理对象,来替代原本需要代码实现的过程。动态代理有着很多优秀的特性,比如代码简洁,易维护等等。 MyBatis动态代理是什么? MyBati…

    Java 2023年5月20日
    00
  • SpringBoot实现物品收藏功能

    下面为你详细讲解如何使用 SpringBoot 实现物品收藏功能: 概述 使用 SpringBoot 可以简单快捷地实现 Web 应用的开发,本文将以 SpringBoot 为基础,使用 Maven 作为项目构建工具,使用 Thymeleaf 模板引擎渲染页面,使用 Hibernate 框架操作 MySQL 数据库,实现物品收藏功能。 前期准备 工具准备 I…

    Java 2023年5月23日
    00
  • maven三个常用的插件使用介绍

    下面我就为您详细讲解“Maven 三个常用的插件使用介绍”的完整攻略,包括介绍、示例和操作流程,以及实际应用案例,希望能给您带来一些帮助。 什么是 Maven 插件? Maven 插件是一些可重用的代码块,可以在 Maven 构建过程中执行特定的任务或目标。Maven 有许多插件可用,而每个插件都提供了在 Maven 构建生命周期的不同阶段执行的一些目标。 …

    Java 2023年5月20日
    00
  • 微信公众号服务号推送模板消息设置方法(后端java)

    下面是详细的攻略: 微信公众号服务号推送模板消息设置方法 开启模板消息功能 要使用模板消息功能,首先需要在公众号后台开启该功能。具体操作步骤如下: 登录公众号后台,在左侧菜单栏中选择“开发者工具”。 点击页面上方的“接口权限”选项卡,找到“模板消息”并开启该功能。 开启模板消息功能后,需要到“模板消息”选项中添加至少一个消息模板。在添加模板时需要提供模板的标…

    Java 2023年5月20日
    00
  • 什么是volatile关键字?

    什么是volatile关键字? volatile是C语言关键字之一,用于修饰变量。 通常情况下,当一个变量被定义后,系统在运行时会在内存中为其分配一块地址,该变量被存储在该内存地址中。当程序运行时会从该地址中读取该变量的值,不过在实际的程序中,可能会遇到一些特殊情况,这些特殊情况可能会导致该变量的值不再在该内存地址中,而是在其他位置上,这个时候就可以通过vo…

    Java 2023年5月10日
    00
  • Java利用哈夫曼编码实现字符串压缩

    Java利用哈夫曼编码实现字符串压缩 介绍 哈夫曼编码是一种可变长度编码,它在通信和数据压缩领域得到广泛的应用。在哈夫曼编码中,出现频率高的字符或词语将被分配短的编码,出现频率低的则分配长的编码,这样可以有效地减少数据的传输量和存储空间。 本攻略将介绍如何使用Java实现字符串的压缩和解压缩,其中包括使用哈夫曼编码来实现压缩。 步骤 以下是压缩和解压缩的完整…

    Java 2023年5月20日
    00
  • JSP常用七大动作指令实例解析

    下面我来为您介绍“JSP常用七大动作指令实例解析”的完整攻略。 什么是JSP动作指令 JSP动作指令是一种特殊的标记,用于在JSP页面中指定特定的处理操作。每个指令都有一个特定的功能,并且在JSP页面的不同部分中使用。JSP标准标签库(JSTL)和自定义标签库都是由JSP动作指令实现的。 JSP常用七大动作指令 1. <%@ page %>指令 …

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部