zoukankan      html  css  js  c++  java
  • 【设计模式(23)】行为型模式之访问者模式

    个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道

    如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充


    生活中,同一类对象会存在不同的元素,每种元素也存在多种不同的逻辑和处理方式。

    比如医生开的处方药,医生会给出不同的组合,患者也有不同的剂量和使用方式;电脑中的不同零件,我们需要根据不同的需求进行采购和组合,以及使用;

    这些数据结构相对稳定,但访问方式多种多样。

    我们可以用访问者模式,把访问方式从数据结构分离出来,并根据需求定制处理方法。进而避免在扩展的时候,修改数据结构。


    1.定义

    使用目的:将数据结构与数据操作分离

    使用时机:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。

    解决问题:稳定的数据结构和易变的操作耦合问题。

    实现方法:在被访问的类里面加一个对外提供接待访问者的接口。

    应用实例:计算机中的组件;医生开的药;

    优点

    • 符合单一职责原则。
    • 优秀的扩展性。
    • 灵活性高。

    缺点

    • 具体元素对访问者公布细节,违反了迪米特原则。
    • 具体元素变更比较困难。
    • 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。

    注意事项:访问者可以对功能进行统一,可以做报表、UI、拦截器与过滤器。


    2.结构

    访问者模式包含以下主要角色。

    • 抽象访问者(Visitor)角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
    • 具体访问者(ConcreteVisitor)角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
    • 抽象元素(Element)角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
    • 具体元素(ConcreteElement)角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
    • 对象结构(Object Structure)角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

    访问者(Visitor)模式的结构图


    3.步骤

    1. 创建抽象访问者

      interface ComputerPartVisitor {
          void visit(Computer computer);
      
          void visit(Mouse mouse);
      
          void visit(Keyboard keyboard);
      }
      
    2. 创建抽象元素类

      interface ComputerPart {
          void accept(ComputerPartVisitor computerPartVisitor);
      }
      
    3. 创建具体元素类

      // 具体元素类-computer
      class Computer implements ComputerPart {
          private List<ComputerPart> parts;
      
          public Computer() {
              parts = List.of(new Mouse(), new Keyboard());
          }
      
          @Override
          public void accept(ComputerPartVisitor computerPartVisitor) {
              parts.forEach(m -> m.accept(computerPartVisitor));
              computerPartVisitor.visit(this);
          }
      }
      
      // 具体元素类-mouse
      class Mouse implements ComputerPart {
          @Override
          public void accept(ComputerPartVisitor computerPartVisitor) {
              computerPartVisitor.visit(this);
          }
      }
      
      // 具体元素类-keyboard
      class Keyboard implements ComputerPart {
          @Override
          public void accept(ComputerPartVisitor computerPartVisitor) {
              computerPartVisitor.visit(this);
          }
      }
      
    4. 创建具体访问者

      // 具体访问者
      class ComputerPartDisplayVisitor implements ComputerPartVisitor {
          @Override
          public void visit(Computer computer) {
              System.out.println("Displaying Computer.");
          }
      
          @Override
          public void visit(Mouse mouse) {
              System.out.println("Displaying Mouse.");
          }
      
          @Override
          public void visit(Keyboard keyboard) {
              System.out.println("Displaying Keyboard.");
          }
      }
      

    测试代码

    public class VisitorTest {
        public static void main(String[] args) {
            ComputerPart computer = new Computer();
            computer.accept(new ComputerPartDisplayVisitor());
    
            System.out.println("------------------------");
            ComputerPart mouse = new Mouse();
            mouse.accept(new ComputerPartDisplayVisitor());
    
            System.out.println("------------------------");
            ComputerPart keyboard = new Keyboard();
            keyboard.accept(new ComputerPartDisplayVisitor());
        }
    }
    

    运行结果

    image-20210722152004405


    4.扩展

    据说访问者模式在开发中使用较为频繁,通常与下面两种设计模式联用

    • 迭代器模式:访问者模式中的对象结构是一个包含元素角色的容易,因此我们在遍历容器中的所有元素时,可以使用迭代器模式来提供迭代器

      虽然我感觉Java8提供的流处理就好。。。

    • 组合模式:访问者模式中的元素对象,可能是叶子对象或者容器对象,如果元素对象是容器对象,那么就必须使用组合模式


    后记

    据说使用很频繁。。。很。。。频繁吗?


    作者:Echo_Ye

    WX:Echo_YeZ

    Email :echo_yezi@qq.com

    个人站点:在搭了在搭了。。。(右键 - 新建文件夹)

  • 相关阅读:
    【NOI2000T4】单词查找树-trie树
    【POJ1698】Alice's Chance-二分图多重匹配
    【POJ1698】Alice's Chance-二分图多重匹配
    【POJ3159】Candies-差分约束系统
    【POJ3159】Candies-差分约束系统
    【POJ2914】Minimum Cut-无向图的全局最小割
    【POJ2914】Minimum Cut-无向图的全局最小割
    【HDU3555】Bomb-数位DP入门题
    【HDU3555】Bomb-数位DP入门题
    codevs 2018 反病毒软件
  • 原文地址:https://www.cnblogs.com/silent-bug/p/15073901.html
Copyright © 2011-2022 走看看