首页 > 其他分享 >访问者模式的理解和实践

访问者模式的理解和实践

时间:2024-12-09 21:56:34浏览次数:6  
标签:salary Visitor void 实践 理解 数据结构 public 访问者

        在软件开发过程中,设计模式为我们提供了解决常见问题的最佳实践。访问者模式(Visitor Pattern)是行为设计模式之一,它将数据操作与数据结构分离,使得在不修改数据结构的前提下,能够定义作用于这些元素的新的操作。本文将详细讲解访问者模式的概念、原理、优缺点,并通过Java代码示例展示其在实际项目中的应用。

 

一、访问者模式的概念

        访问者模式是一种将数据操作与数据结构分离的设计模式。它通过将作用于某种数据结构中的各元素的操作封装起来,使得这些操作可以独立于数据结构进行变化。访问者模式使得我们能够在不修改数据结构的前提下,增加新的操作。

二、访问者模式的结构

        访问者模式包含以下几个角色:

  1. Visitor(访问者):接口或抽象类,声明了访问者对各个元素的操作方法。
  2. ConcreteVisitor(具体访问者):实现了Visitor接口或抽象类,具体实现了对各个元素的操作。
  3. Element(元素):接口或抽象类,声明了接受访问者的方法。
  4. ConcreteElement(具体元素):实现了Element接口或抽象类,存储数据,并实现了接受访问者的方法。
  5. ObjectStructure(对象结构):包含多个元素,可以迭代这些元素,并允许访问者访问这些元素。

三、访问者模式的原理

        访问者模式的原理是将操作从数据结构中分离出来,封装到访问者类中。数据结构中的每个元素都接受访问者对象,访问者对象通过访问这些元素来执行相应的操作。这样,当需要增加新的操作时,只需新增一个访问者类,而无需修改数据结构。

四、访问者模式的优缺点

优点

  1. 增加新的操作很容易:只需增加一个新的访问者类,而无需修改已有的数据结构。
  2. 将数据操作集中管理:访问者模式将相关的操作集中到一个访问者类中,便于管理。
  3. 分离了数据结构和操作:数据结构和操作不再耦合在一起,提高了系统的灵活性。

缺点

  1. 增加了类的数量:每增加一个新的操作,都需要增加一个新的访问者类,增加了类的数量。
  2. 破坏了封装:访问者需要访问被访问对象的内部结构,这在一定程度上破坏了封装性。
  3. 增加了系统复杂度:访问者模式的实现相对复杂,需要理解其工作原理,才能正确使用。

五、访问者模式的实践

        下面通过Java代码示例,展示访问者模式在实际项目中的应用。

示例背景

        假设我们有一个简单的员工管理系统,员工分为两类:工程师(Engineer)和经理(Manager)。我们需要实现两个操作:计算工资(CalculateSalary)和显示员工信息(DisplayInfo)。

代码实现

定义Element接口

// 定义Element接口
public interface Element {
    void accept(Visitor visitor);
}

定义具体元素类

// 定义工程师类
public class Engineer implements Element {
    private String name;
    private int salary;

    public Engineer(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

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

// 定义经理类
public class Manager implements Element {
    private String name;
    private int salary;
    private int bonus;

    public Manager(String name, int salary, int bonus) {
        this.name = name;
        this.salary = salary;
        this.bonus = bonus;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    public int getBonus() {
        return bonus;
    }

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

定义Visitor接口

// 定义Visitor接口
public interface Visitor {
    void visit(Engineer engineer);
    void visit(Manager manager);
}

定义具体访问者类

// 定义计算工资访问者类
public class CalculateSalaryVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer " + engineer.getName() + " salary: " + engineer.getSalary());
    }

    @Override
    public void visit(Manager manager) {
        int totalSalary = manager.getSalary() + manager.getBonus();
        System.out.println("Manager " + manager.getName() + " salary: " + totalSalary);
    }
}

// 定义显示信息访问者类
public class DisplayInfoVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer: " + engineer.getName());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Manager: " + manager.getName() + ", Bonus: " + manager.getBonus());
    }
}

定义ObjectStructure类

import java.util.ArrayList;
import java.util.List;

// 定义ObjectStructure类
public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

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

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

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

客户端代码

public class Client {
    public static void main(String[] args) {
        ObjectStructure os = new ObjectStructure();

        os.addElement(new Engineer("John Doe", 70000));
        os.addElement(new Manager("Jane Smith", 80000, 10000));

        Visitor calculateSalaryVisitor = new CalculateSalaryVisitor();
        os.accept(calculateSalaryVisitor);

        System.out.println("------");

        Visitor displayInfoVisitor = new DisplayInfoVisitor();
        os.accept(displayInfoVisitor);
    }
}


运行结果

Engineer John Doe salary: 70000
Manager Jane Smith salary: 90000
------
Engineer: John Doe
Manager: Jane Smith, Bonus: 10000


总结

        访问者模式通过将操作从数据结构中分离出来,提高了系统的灵活性和可扩展性。它使得在不修改数据结构的前提下,能够增加新的操作。然而,访问者模式也增加了类的数量,破坏了封装,增加了系统的复杂度。因此,在实际应用中,我们需要根据具体需求权衡利弊,选择是否使用访问者模式。

        通过上面的示例,我们可以看到访问者模式在员工管理系统中的应用,通过定义不同的访问者类,实现了计算工资和显示员工信息的功能。这使得系统的操作更加灵活,易于扩展和维护。希望这篇文章能够帮助大家更好地理解访问者模式,并在实际项目中灵活运用。

标签:salary,Visitor,void,实践,理解,数据结构,public,访问者
From: https://blog.csdn.net/huaqianzkh/article/details/144358460

相关文章

  • 【论文系列】PPO知识点梳理 (尽我可能细致通俗理解!)
    零、题记这篇博客一方面为了记录当前的知识点,另一方面PPO算法实在是太重要了,不但要从理论上理解它到底是怎样实现的,还需要从代码方面进行学习和记录,这里我就通俗的将这个知识点进行简单的记录,用来日后我自己的巩固和大家的交流学习。下面均是我自己个人见解,如有不对之处,欢迎评论......
  • Jetpack Compose 入门与深入理解(一)
    JetpackCompose命令式UI(ImperativeUI)什么是命令式UI命令式UI的缺点声明式UI(DeclarativeUI)什么是声明式UI声明式UI的优点声明式UI发展历程命令式UI(ImperativeUI)什么是命令式UI在Android开发中,我们目前采用命令式UI开发模式<!--代码经过简化--><LinearLa......
  • GLM-4V-Flash:智谱 AI 免费开放的图像理解大模型 API 接口
    ❤️如果你也关注AI的发展现状,且对AI应用开发非常感兴趣,我会每日跟你分享最新的AI资讯和开源应用,也会不定期分享自己的想法和开源实例,欢迎关注我哦!......
  • 解题报告-论对“分组背包”的新理解
    解题报告-论对“分组背包”的新理解分组背包都知道,但是有一种新式分组背包,它不像我们想的那样每组只能选一个,但是这样的背包问题又是与分组强相关的,那么怎么做呢?这道题、这道题和这道题就是这种分组背包的典范。这种背包问题的共同特征是:选完一组背包中的上一个后,才能选下一个。......
  • 深入理解PrimeFaces DataTable的懒加载分页机制
    在现代Web应用开发中,处理大量数据时,性能和用户体验是至关重要的。PrimeFacesDataTable组件提供了一种懒加载(lazyloading)机制,允许我们分批次加载和显示大量数据,而不是一次性加载所有数据。本文将通过一个具体的实例,详细解释如何利用PrimeFaces、JPA、Hibernate和H2内存数据......
  • 深入理解Servlet错误处理机制
    深入理解Servlet错误处理机制在Web开发中,错误处理是一个不可忽视的重要环节。正确地处理错误不仅能提升用户体验,还能帮助开发者快速定位问题。本文将详细介绍如何在Servlet中配置和处理错误,并通过实例来展示这一过程。配置错误页面在Servlet中,我们可以通过在web.xml文件......
  • 【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
    目录......
  • 分享一个对STM32 ADC单次转换模式、连续转换模式扫描模式的理解
    目录不启动SCAN模式在单次转换模式下:启动SCAN模式下在连续转换模式下此随笔出自对STM32ADC单次转换模式、连续转换模式扫描模式的理解举例用ADC1规则通道的顺序为CH0,CH1,CH2,CH3不启动SCAN模式在单次转换模式下:启动ADC1,则1.开始转换CHO(ADCSQR的第一通道)2.转换完成......
  • 深入理解 Druid 数据库连接池配置
    深入理解Druid数据库连接池配置在现代应用程序中,数据库连接池是提高数据库访问性能和资源利用率的关键组件之一。Druid是一个高性能的数据库连接池,广泛应用于Java应用程序中。本文将详细介绍如何配置Druid数据库连接池,并通过properties文件、YAML文件和XML文件三种方......
  • 对RNN算法个人觉得理解比较到位的博客摘要,记录一些大佬的博客链接
    题记这篇博客主要记录几个讲的比较不错的博客,方便大家理解RNN系列的优化算法,比如GRU、LSTM等,以及为什么要用,怎么用等问题,我个人读下来是写的比较不错。当然还有一些我觉得比较不错的强化学习方面的博客,也在此浅浅的记录一下。。。正文第一处博客第二处博客这个是PYTORCH的代......