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日

相关文章

  • SpringBoot使用Sharding-JDBC实现数据分片和读写分离的方法

    SpringBoot使用Sharding-JDBC实现数据分片和读写分离的方法 概述 Sharding-JDBC是基于JDBC的分布式数据库中间件,用于替代传统数据库的分布式架构。Sharding-JDBC采用读写分离和数据分片等技术,使得应用程序无需了解底层数据库的实现细节,可以直接访问逻辑表的数据,同时对于外部应用程序的影响也同样降到了最低,非常适合大型…

    Java 2023年5月20日
    00
  • Java新手学习之IO流的简单使用

    Java新手学习之IO流的简单使用 什么是IO流? IO流是Java中的一种文件读写操作方式,用于读写文件、网络通信等。Java中的IO流被分为字节流和字符流两种类型。其中,字节流以单个字节作为读写单位,而字符流以unicode字符作为读写单位。 如何使用IO流读写文件? Java中的IO流提供了FileInputStream和FileOutputStrea…

    Java 2023年5月26日
    00
  • Java计时新姿势StopWatch详解

    Java计时新姿势StopWatch详解 在Java应用程序中,需要对部分代码块的执行时间进行计时,以便进行性能优化和代码调试。在Java中有多种计时方式,其中一个使用较为广泛且方便的库就是StopWatch。 StopWatch简介 StopWatch是Spring框架中的一个计时器工具类,其原理是基于System.currentTimeMillis(),…

    Java 2023年5月20日
    00
  • 修改Tomcat默认访问根目录的方法

    当我们访问Tomcat服务器时,它默认会加载webapps目录下的ROOT应用程序。但是,有时我们想在不改变应用程序名称的情况下将默认访问目录更改为不同的目录。接下来,我将向您介绍如何在Tomcat服务器中修改默认访问目录的方法。 步骤一:定位server.xml文件 Tomcat服务器的配置文件位于Tomcat安装目录下的conf目录中。在此目录中,我们可…

    Java 2023年5月19日
    00
  • Javafx简单实现【我的电脑资源管理器】效果

    下面是详细讲解“Javafx简单实现【我的电脑资源管理器】效果”的完整攻略: 1. 准备工作 在进行Javafx开发前,我们需要先安装好开发所需的环境,包括JDK和IDE。这里我们选择JDK1.8和Intellij IDEA作为开发环境。具体安装方法这里不作过多说明,可以参考官方文档进行安装。 2. 建立项目 使用Intellij IDEA创建一个新的Jav…

    Java 2023年5月24日
    00
  • Spring Data Jpa 复杂查询方式总结(多表关联及自定义分页)

    下面就是 Spring Data JPA 复杂查询方式的攻略: 概述 Spring Data JPA 提供 JPA 规范标准的数据访问方式,并简化了持久层的开发。在实际应用场景中,有些查询需要多表关联及自定义分页方式。 本文将介绍 Spring Data JPA 多表关联及自定义分页的实现方式。 多表关联查询 基于 JPA 查询 在 JPA 中,我们可以通过…

    Java 2023年6月2日
    00
  • shiro与spring security用自定义异常处理401错误

    我将为您详细讲解 “Shiro与Spring Security用自定义异常处理401错误”的完整攻略。 首先,我们先了解一下什么是401错误。401错误表示未经授权或身份验证失败。在Shiro和Spring Security中,当用户获取未授权的访问时,系统将返回401错误。 接着,我们可以通过自定义异常处理程序来处理401错误。 一、Shiro的自定义异常…

    Java 2023年5月20日
    00
  • win7系统打开java的控制面板的方法

    要在Win7系统上打开Java控制面板,可按照以下步骤进行操作: 方法一:使用Windows搜索功能打开Java控制面板 点击Windows系统右下角的“开始”按钮; 在开始菜单中,点击“搜索程序和文件”栏目输入“Java”; 在搜索结果中,找到并点击“Java”选项; 在弹出的Java应用程序窗口中,点击“Java 控制面板”按钮。 示例一: 步骤1:在窗…

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