前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >22.设计模式--访问者模式(Visitor模式)

22.设计模式--访问者模式(Visitor模式)

作者头像
大猫的Java笔记
发布2021-11-30 11:39:07
3310
发布2021-11-30 11:39:07
举报
文章被收录于专栏:大猫的Java笔记大猫的Java笔记

1.定义

访问模式是一种行为型模式,访问者模式的定义:“表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作”。

前面我们学习了组合模式,组合模式可以让我们快速构建树,对于数据结构来说,树的怎么定义实际上就是一种数据结构,而对于树的遍历操作等可以交给访问者来做,这样的好处是,首先进一步做了分离,操作和具体实现的分离,同时按照访问者的定义来说即使将来需要新增对元素的操作,也可以不改变各个元素的类。

2.访问者模式结构图

Visitor是抽象的访问者,定义谁可以被访问者,图中的ConcreteElementA和ConcreteElementB的两个参数就是具体可以被访问的实体。

当然对于访问者来说不可能访问了啥事不干吧,你要去拜访一个人也得因为什么事情要去,即使只是去蹭个饭,聊个天。所以ConcreteVisitor是访问者具体要做的事。

Element则是用于接受访问者,抽象的被访问者,相当于就是一个主人,你要去访问一个人,而这个人的抽象就是Element。

ConcreteElementA和ConcreteElementB都是被访问者的具体实现。也就是具体的被访问的人。

ObjectStructure是对象结构,我们说访问者是在不改变原元素的情况下增加新的功能,而这个ObjectStructure你可以理解为就是我们的数据结构,例如构成树的类,或组合模式中的部门和人员,文件或文件夹等。

3.访问者模式实现

Visitor是抽象的访问者,只是简单的定义了要访问谁,可以看到可以访问的是部门类和人员类(之前组合模式中的类),而具体的要怎么访问,访问了要干什么?哪怕是去蹭饭,去聊天,都应该由子类决定。

代码语言:javascript
复制
public abstract class Visitor {

    public abstract void visit(Department department);

    public abstract void visit(Person person);
}

ListVisitor是具体的访问者,具体访问了要干什么都是他来做,而这儿只是对如果是部门的话就输出部门名以及部门下的所有人,而如果只是人的话则打印人的名称。

代码语言:javascript
复制
public class ListVisitor extends Visitor{

    private String currentDir = "";

    @Override
    public void visit(Department department) {
        String name = currentDir + "/" + department;
        System.out.println(name);
        currentDir = name;
        List<OrganizationalStructure> son = department.son;
        for (OrganizationalStructure shuGuo : son) {
            shuGuo.accept(this);
        }
    }

    @Override
    public void visit(Person person) {
        System.out.println(currentDir+"/"+person);
    }
}

Element用于接受访问者,相当于自己就是被访问的,如果有人来访问你,你肯定要去迎接吧,所有accpent就是用于迎接或接受访问者。

代码语言:javascript
复制
public interface  Element {
    /**
     * 用于接受访问者
     * @param visitor
     */
    void accept(Visitor visitor);
}

OrganizationalStructure是之前在组合模式中用到部门和人员的抽象,就是组织结构。只是我们删除了一些对组织结构的遍历的抽象方法,同时实现了Elenent,毕竟OrganizationalStructure就是被访问者,现在有人要访问你,肯定要迎接,那就得实现Element。

代码语言:javascript
复制
public abstract class OrganizationalStructure implements Element {

    /**
     * 获取名称
     * @return
     */
    public abstract String getName();


    @Override
    public String toString() {
        return getName();
    }
}

Department部门类,继承于组织结构,同时现在也是具体的被访问者,毕竟父类实现了Element,实际上Department可以去实现Element类,但是为了让Department和Person都实现于Element,所以采用的是OrganizationalStructure实现于Element。

代码语言:javascript
复制
public class Department extends OrganizationalStructure {

    /**
     * 部门名
     */
    private String name;

    /**
     * 部门中的人员或下级部门
     */
    public List<OrganizationalStructure> son = new ArrayList();


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

    /**
     * 获取部门名称
     * @return
     */
    @Override
    public String getName() {
        return name;
    }


    /**
     * 当前部门添加子部门或人员信息
     * @param shuGuo
     * @return
     */
    public OrganizationalStructure add(OrganizationalStructure shuGuo){
        son.add(shuGuo);
        return this;
    }

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

}

同理对于Person来说也是组织结构的一部分,所以也继承于OrganizationalStructure,当然也实现了accept方法,而对于accept方法来说,accept方法使用visitor.visit(this)相当于将访问者要访问的人设置了自己。

代码语言:javascript
复制
public class Person extends OrganizationalStructure {

    /**
     * 人员名称
     */
    private String name;

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

    /**
     * 获取人员名
     * @return
     */
    @Override
    public String getName() {
        return name;
    }


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

而现在构建组织结构后,不再像组合模式中调用printList方法进行结构的打印,而是使用访问者模式,相当于将结构和功能做了一个拆分;如果后续需要对组织结构增加新的打印方式,此时对于部门和人员类来说是不需要发生变化的,这就是访问模式的优势。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Department department1 = new Department("谋士部");
        Department department2 = new Department("武将部");
        department1.add(new Person("诸葛亮"));
        department1.add(new Person("庞统"));
        department1.accept(new ListVisitor());
        System.out.println();
        department2.add(new Person("张飞"));
        department2.add(new Person("赵云"));
        department2.add(new Person("黄忠"));
        department2.add(new Person("马超"));
        department2.add(new Person("关羽"));
        Department department3 = new Department("弓箭部");
        department3.add(new Person("小兵1"));
        department3.add(new Person("小兵2"));
        department2.add(department3);
        department2.accept(new ListVisitor());
    }
}
代码语言:javascript
复制
/谋士部
/谋士部/诸葛亮
/谋士部/庞统

/武将部
/武将部/张飞
/武将部/赵云
/武将部/黄忠
/武将部/马超
/武将部/关羽
/武将部/弓箭部
/武将部/弓箭部/小兵1
/武将部/弓箭部/小兵2

访问者模式中的角色

抽象访问者(Visitor):抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是 visit 方法的参数定义哪些对象是可以被访问的; 文中相当于Visitor。

具体访问者(ConcreteVisitor):访问者访问到一个类后该怎么干(哎,这个别读歪了),要做什么事情;文中相当于ListVisitor。

抽象元素(Element):接口或者抽象类,声明接受那一类型的访问者访问,程序上是通过 accept 方法 中的参数来定义;文中相当于Element类。

具体元素:(ConcreteElement):实现 accept 方法,通常是 visitor.visit(this),文中相当于部门以及人员类。

结构对象(ObjectStruture):容纳多个不同类、不同接口的容器,比如 List、Set、Map 等,在项目中, 一般很少抽象出来这个角色;

参考文献《图解设计模式》

代码获取地址:https://gitee.com/bughong/design-pattern

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大猫的Java笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档