zoukankan      html  css  js  c++  java
  • 行为型模式:访问者模式

    文章首发:
    行为型模式:访问者模式

    如画

    十一大行为型模式之十一:访问者模式。

    简介

    姓名 :访问者模式
    英文名 :Visitor Pattern
    价值观 :来访者便是客,招待就是
    个人介绍
    Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
    封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
    (来自《设计模式之禅》)

    你要的故事

    先声明一下,下面故事全瞎编的。。。

    我们是否还记得 N 年前反腐开始的时候,有一段时间提倡官员宴请吃饭只能几菜几汤,不能超出。我记得那会刚读大一,军事理论的老师说到这个问题,也发表了他的一些想法,他觉得这么做比较刻板。今天的故事就和宴请有关。现在中国企业发展越来越大,在社会中担任的责任也越来越大,政府也越来越重视企业,官员去参观企业是常有的事,而企业宴请官员也变得格外的常见。

    故事的背景就是企业宴请各级官员。不同级别的官员宴请的菜式就不一样,每家企业的菜式丰富程度也不一样。我们这里的访问对象就用 Alibaba 和 Tencent 这 2 家公司,而访问者就用郭嘉领导人和省领导人做举例。这 2 家公司都跟喜来登酒店合作,Alibaba 合作方案是:宴请省级领导人及以下官员则十菜一汤,宴请郭嘉领导人及以上官员则十四菜两汤;Tencent 合作方案是:宴请省领导人及以下官员则八菜一汤,宴请郭嘉领导人及以上官员则十六菜两汤。

    下面看看如何用访问者模式来实现上面的故事。

    首先定义一个抽象类:企业。企业有一个共有的特性就是接受上级领导的访问。

    /**
     * 企业
     */
    abstract class Company {
    
        public abstract void accept(Vistor vistor);
    
    }
    

    上面故事我们举例了 2 家企业,分别是 Alibaba 和 Tencent,这里实现这 2 家公司的宴请方案,并实现接待访问者方法。

    Alibaba 宴请郭嘉领导人及以上官员是十四菜两汤,宴请省领导及以下是十菜一汤。

    /**
     * Alibaba 企业
     */
    class AlibabaCompany extends Company {
    
        @Override
        public void accept(Vistor vistor) {
            vistor.visit(this);
        }
    
        public String entertainBelowProvincialLeader(String leader) {
            return "Alibaba 接待" + leader + ":十菜一汤";
        }
    
        public String entertainAboveNationalLeader(String leader) {
            return "Alibaba 接待" + leader + ":十四菜两汤";
        }
    
    }
    

    Tencent 宴请郭嘉领导人及以上是十六菜两汤,宴请省领导及以下是八菜一汤。

    /**
     * Tencent 企业
     */
    class TencentCompany extends Company {
    
        @Override
        public void accept(Vistor vistor) {
            vistor.visit(this);
        }
    
        public String entertainBelowProvincialLeader(String leader) {
            return "Tencent 接待" + leader + ":八菜一汤";
        }
    
        public String entertainAboveNationalLeader(String leader) {
            return "Tencent 接待" + leader + ":十六菜两汤";
        }
    }
    

    这里定义访问者接口,访问者接口有 2 个方法,分别是访问 Alibaba 企业和访问 Tencent 企业。

    /**
     * 访问者接口
     */
    interface Vistor {
    
        void visit(AlibabaCompany alibabaCompany);
    
        void visit(TencentCompany tencentCompany);
    
    }
    

    上面故事中有 2 个访问者,一个是郭嘉领导人,另一个是省领导人,因为不同企业对应不同访问者有不同的宴请方案,所以这里访问企业是需要调用对应企业的宴请方式。

    省领导人访问企业时,需要调用企业对省领导及以下官员的宴请方案,为entertainBelowProvincialLeader()

    /**
     * 省领导访问
     */
    class ProvincialLeaderVistor implements Vistor {
    
        @Override
        public void visit(AlibabaCompany alibabaCompany) {
            System.out.println(alibabaCompany.entertainBelowProvincialLeader("省领导"));
        }
    
        @Override
        public void visit(TencentCompany tencentCompany) {
            System.out.println(tencentCompany.entertainBelowProvincialLeader("省领导"));
        }
    }
    

    郭嘉领导人访问企业时,需要调用企业对郭嘉领导人的宴请方案,为entertainAboveNationalLeader()

    /**
     * 郭嘉领导访问
     */
    class NationalLeaderVistor implements Vistor {
    
        @Override
        public void visit(AlibabaCompany alibabaCompany) {
            System.out.println(alibabaCompany.entertainAboveNationalLeader("省领导"));
        }
    
        @Override
        public void visit(TencentCompany tencentCompany) {
            System.out.println(tencentCompany.entertainAboveNationalLeader("郭嘉领导"));
        }
    }
    

    上面是访问者和被访问者的代码,因为企业是在喜来登酒店宴请领导人,所以这里还需要一个酒店,酒店里面有企业合作的名单,以及负责宴请各路领导的方法提供。

    /**
     * 酒店
     */
    class Hotel {
        private List<Company> companies = new ArrayList<>();
    
        public void entertain(Vistor vistor) {
            for (Company company : companies) {
                company.accept(vistor);
            }
        }
    
        public void add(Company company) {
            companies.add(company);
        }
    }
    

    下面提供测试代码,看看运行的结果怎样。

    public class VisitorTest {
    
        public static void main(String[] args) {
            AlibabaCompany alibabaCompany = new AlibabaCompany();
            TencentCompany tencentCompany = new TencentCompany();
            ProvincialLeaderVistor provincialLeaderVistor = new ProvincialLeaderVistor();
            NationalLeaderVistor nationalLeaderVistor = new NationalLeaderVistor();
    
            Hotel xilaideng = new Hotel();
            xilaideng.add(alibabaCompany);
            xilaideng.add(tencentCompany);
    
            xilaideng.entertain(provincialLeaderVistor);
            xilaideng.entertain(nationalLeaderVistor);
        }
    
    }
    
    打印结果:
    Alibaba 接待省领导:十菜一汤
    Tencent 接待省领导:八菜一汤
    Alibaba 接待郭嘉领导:十四菜两汤
    Tencent 接待郭嘉领导:十六菜两汤
    

    完整的访问者模式代码已经呈现,花 1 分钟思考一番,理解整个代码后我们来看看下面的总结。

    总结

    访问者模式有比较好的扩展性,看看访问者代码,我们如果要新增一个访问者:市领导人,只需新增市领导人类,便可实现。当然也有它不好的地方,就是把被访问者暴露给访问者,使得访问者可以直接了解被访问者的所有东西。明白了优缺点,才能更好的在实际中运用,一般访问者模式运用于要求遍历多个不同的对象的场景。

    推荐阅读

    行为型模式:解释器模式

    行为型模式:观察者模式

    行为型模式:迭代器模式

    设计模式系列文章持续更新中,欢迎关注公众号 LieBrother,一起交流学习。
    公众号后台回复『大礼包』获取 Java、Python、IOS 等教程
    加个人微信备注『教程』获取架构师、机器学习等教程

    LieBrother

  • 相关阅读:
    java动态代理机制
    Spring的几种注入bean的方式
    java的泛型与反射机制
    java中equals与==的比较
    Java虚拟机JVM简单理解
    java集合类总结
    timersmanager 解析
    rtsp实时流通过rtmp推送到服务端
    udp 视频包网络传输花屏
    GB28181国检推流
  • 原文地址:https://www.cnblogs.com/liebrother/p/10714875.html
Copyright © 2011-2022 走看看