和 lvgo 一起学设计模式(二十二)行为型之访问者模式

↑点击蓝字关注,支持原创作者

进修凡尔赛文学

访问者模式

将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。

刚看到这个模式的时候,我人都傻了,完全不知道说的是啥,直到看了近5份资料!才搞清楚这个设计模式,不愧是最复杂的一种,我也这样觉得。不过千万别被复杂吓到,捋清了之后,还是比较简单的。

开门见山

访问者模式“人如其名”,就是说不同的访问者对同一个对象的访问结果不同。为什么会不同呢?因为这个访问者是我们自己定义的,我们就想让他不同😂。

而实际情况更是如此。我通过几份资料总结下来,这个访问者模式所谓的访问者其实就是我们想要控制的访问权限一样。因为任何一个“访问者”都可以看到具体数据的全部内容,他只是选择性的"不看“,这样便区分开了”访问者“「关注的内容」,或者 「限制」访问者「权限」

可能我说的有点绕,有点抱歉,我再简化一下这个内容。

网络用语

「抛开表象看本质」

如果我们抛开访问者模式这些专业的定义,单纯的去理解这个访问者模式要表达的意思,我觉得用一个东西最合适不过。那就是“网络用语”;

不知道大家听没听过前阵子火了的百度广告《你说啥》单曲。歌曲中的朝阳大妈就是一个不知道关注点或者是被限制了访问权限的访问者,当然他歌曲中说的网络语有好多我也不知道是啥🙃。没听过的快去听吧。

还有最近的 凡尔赛文学 我不百度的时候以为是个地名,所以我的 权限 也被限制了。

正好提到这个了,那我们就拿 凡尔赛文学 这个网络语来学习一下访问者模式吧~🤩

凡尔赛文学

「首先我们就要再一次抛开表象看本质😂」

下面是我搜集到有关凡尔赛的释义:

  1. 凡尔赛是法国巴黎的卫星城以及伊夫林省省会,曾是法兰西王朝的行政中心。
  2. 《凡尔赛》是皮埃尔·苏勒执导的剧情片。
  3. 以法国路易十四为时代背景的电视剧。
  4. 凡尔赛文学,网络热词,指通过先抑后扬、自问自答或第三人称视角,不经意间露出"贵族生活的线索"。
  5. 啥???

对于凡尔赛一共有 5 种释义,他的结构应该是这样的

public class Versailles {

    private final String interpretation1 = "凡尔赛是法国巴黎的卫星城以及伊夫林省省会,曾是法兰西王朝的行政中心。";
    private final String interpretation2 = "《凡尔赛》是皮埃尔·苏勒执导的剧情片。";
    private final String interpretation3 = "以法国路易十四为时代背景的电视剧。";
    private final String interpretation4 = "凡尔赛文学,网络热词,指通过先抑后扬、自问自答或第三人称视角,不经意间露出\"贵族生活的线索\"。";
    private final String interpretation5 = "啥???";
    
}

因为我们还要对这个数据进行访问,所以还要给他加个访问的方法 #visit

public class Versailles {

   .....
       ....
       ...
    /*
     * 访问
     */

    public void visit(){

    }
}

既然要访问,肯定要有访问者啊,因为访问者挺多的,比如我、我的小伙伴、还有你。

所以我们就使用依赖倒置原则来定义一个访问者接口 Visitor 然后有个访问方法,再把凡尔赛给访问者去让其自己访问,那代码实现起来应该是这样的。

Visitor接口

public interface Visitor {
    void visit(Versailles versailles);
}

凡尔赛的访问方法调整一下,最终完整类如下

public class Versailles {

    private final String interpretation1 = "凡尔赛是法国巴黎的卫星城以及伊夫林省省会,曾是法兰西王朝的行政中心。";
    private final String interpretation2 = "《凡尔赛》是皮埃尔·苏勒执导的剧情片。";
    private final String interpretation3 = "以法国路易十四为时代背景的电视剧。";
    private final String interpretation4 = "凡尔赛文学,网络热词,指通过先抑后扬、自问自答或第三人称视角,不经意间露出\"贵族生活的线索\"。";
    private final String interpretation5 = "啥???";

    /**
     * 将该对象提供给访问者访问
     * @param visitor 访问者
     * 方法名改成 accept 更好,表示这个类接受一个访问者来访问自己🙅
     */

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

接下来就是具体的访问者了,那我根据实际情况来定义一些访问者

  1. I
  2. MyFriend
  3. You

一共三个访问者

「I」(我自己)

我比较博学多识,我知道凡尔赛是地名、电影、电视剧三个

「MyFriend」(狗哥)

看他的样子应该是不知道

狗哥一问三不知

「You」(你呢?)

我就当你知道凡尔赛文学,已经领悟到了无形装逼的境界好了🌚

看下这三个类的情况

/**
 * 我比较博学多识
 * <p>
 * 欢迎跟我一起学习,微信(lvgocc)公众号搜索:星尘的一个朋友
 *
 * @author lvgorice@gmail.com
 * @version 1.0
 * @blog @see http://lvgo.org
 * @CSDN @see https://blog.csdn.net/sinat_34344123
 * @date 2020/12/1
 */

public class I implements Visitor {
    @Override
    public void visit(Versailles versailles) {
        System.out.println(versailles.getInterpretation1());
        System.out.println(versailles.getInterpretation2());
        System.out.println(versailles.getInterpretation3());
    }
}
// 弱智狗哥
public class MyFriend implements Visitor {
    @Override
    public void visit(Versailles versailles) {
        System.out.println(versailles.getInterpretation5());
    }
}
// 网络达人
public class You implements Visitor {
    @Override
    public void visit(Versailles versailles) {
        System.out.println(versailles.getInterpretation4());
    }
}

最后我们在模拟一下运行起来的情况

class VisitorTest {

    @Test
    void visit() {
        Versailles versailles = new Versailles();

        System.out.println("lvgo 你知道凡尔赛吗?");
        versailles.accept(new I());

        System.out.println("\n狗哥 你知道凡尔赛吗?");
        versailles.accept(new MyFriend());
        
        System.out.println("\n你知道凡尔赛吗?");
        versailles.accept(new You());
    }
}

结果,狗哥拉胯

lvgo 你知道凡尔赛吗?
凡尔赛是法国巴黎的卫星城以及伊夫林省省会,曾是法兰西王朝的行政中心。
《凡尔赛》是皮埃尔·苏勒执导的剧情片。
以法国路易十四为时代背景的电视剧。

狗哥 你知道凡尔赛吗?
啥???

你知道凡尔赛吗?
凡尔赛文学,网络热词,指通过先抑后扬、自问自答或第三人称视角,不经意间露出"贵族生活的线索"

不同的访问者,看到数据结构中的结果不同。再来看下访问者的定义

在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

虽然我们这里用的是一个对象,试着将它变成集合(多个网络语而已)吧。使用循环把每个元素都“送”给访问者,这个就留着给你动手试试吧,也留给自己以后回来看的时候能被逼动动脑😂。实在不想动,关注回复 “源码” 吧!😀

访问者模式类图 📌

最后,我们来看下标准的访问者模式结构图

访问者类图

这个结构比较复杂

  1. 客户端高层模块 Client
  2. 访问者接口,依赖倒置接口 Visitor
  3. 被访问的元素, Element
  4. 最后一个, ObjectStructure 对象结构;

这里唯一可能需要解释的就是这个 ObjectStructure 了,他即用于来定义管理 Element 的对象载体。它可以是我们业务场景中任何需要被访问元素的载体对象,比如上述例子中,我们想把这个结构放进去那我就可以定义一个词语类 Word ,里面可以有 NetWordLanguageProfessional vocabulary 等等对象。如下所示

public class Word {

    /**
     * 网络语
     */

    private final List<NetWordLanguage> netWordLanguages = new ArrayList<>();

    public void addWord(NetWordLanguage netWordLanguage) {
        if (!netWordLanguages.contains(netWordLanguage)){
            netWordLanguages.add(netWordLanguage);   
        }
    }
}

访问者全部源代码关注回复 “源码” 获取

总结 📚

访问者模式适合在「数据结构稳定」的系统中,即很少或不变的数据结构场景;

当你想要对一个数据集合增加一些不同的使用规则,或者是权限控制时,可以考虑使用访问者模式,并要一同考虑数据结构是否稳定(是否会在增加类),因为这会导致访问者需要重构

「解决的问题:」

  1. 访问者模式使数据结构与数据访问分离
  2. 可以很灵活的增加不同的访问规则

「自身的问题:」

  1. 一旦出现数据结构变更(新增类型),将会使访问者发生较大的修改,因为需要调整访问者接口!严重违反了开闭原则

推荐阅读

「如果觉得我写的还行,可以点赞、关注支持,也非常欢迎分享给更多的人,感谢你的阅读」

本文分享自微信公众号 - 星尘的一个朋友(gh_6d8fc35da824)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://my.oschina.net/lvgo/blog/4791009

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario,低调大师唯一一个Java游戏作品

Mario,低调大师唯一一个Java游戏作品

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。

Sublime Text 一个代码编辑器

Sublime Text 一个代码编辑器

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。