阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

详细讲解Java访问者设计模式

284次阅读
没有评论

共计 3651 个字符,预计需要花费 10 分钟才能阅读完成。

导读 大多数情况下你不需要访问者模式,但当一旦需要访问者模式时,那就是真的需要它了,这是设计模式创始人的原话。可以看出应用场景比较少,但需要它的时候是不可或缺的,这篇文章就开始学习最后一个设计模式——访问者模式

编程是一门艺术,大批量的改动显然是非常丑陋的做法,用心的琢磨写的代码让它变的更美观。

在生活中,电影或电视剧中的人物角色,不同的观众对他们的评价也不同;还有顾客在商场购物时放在“购物车”中的商品,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。

这些被处理的数据元素相对稳定而访问方式多种多样的数据结构,如果用“访问者模式”来处理比较方便。访问者模式能把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构,这提高了程序的扩展性和灵活性。

1. 模式的定义

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

访问者设计模式主要解决:java 多态方法重载的静态化问题。

2. 访问者设计模式的优点与不足

访问者(Visitor)模式是一种对象行为型模式,其主要优点:

  • 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  • 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  • 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
  • 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
  • 访问者(Visitor)模式的不足:

  • 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  • 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
  • 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
  • 3. 访问者设计模式的实现思路

    访问者(Visitor)模式实现的关键是如何将作用于元素的操作分离出来封装成独立的类

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

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

    场景介绍:统计不同水果的价格,不同的水果放置到不同的集合,但是由于 java 多态中方法重载是静态化的不足,导致统计不出来价格,就可以使用访问者设计模式来处理。

    public interface Fruit {int price();
        void draw();
        int accept(Visit visit);
    }
    public class Apple implements Fruit {
        private int price = 100;
        public Apple(){}
        public Apple(int price){this.price = price;}
        public void pack(AppleBag bag){bag.pack();
        }
        @Override
        public int price() {return price;}
        @Override
        public void draw() {System.out.print("苹果红富士");
        }
        public void setPrice(int price) {this.price = price;}
        public int accept(Visit visit){
            /* 指针可以传递真实类型 */
            return visit.sell(this);
        }
    }
    public class Banana implements Fruit {
        private int price = 60;
        @Override
        public int price() {return price;}
        public void pack(BananaBag bag){bag.pack();
        }
        @Override
        public void draw() {System.out.print("仙人蕉");
        }
        public int accept(Visit visit){return visit.sell(this);
        }
        public void setPrice(int price) {this.price = price;}
    }
    public class Orange implements Fruit {
        private String name = "";
        private int price = 70;
        public Orange(String name,int price){
            this.price = price;
            this.name = name;
        }
        public void pack(OrangeBag bag){bag.pack();
        }
        @Override
        public int price() {return price;}
        @Override
        public void draw() {System.out.print("砂糖桔");
        }
        public int accept(Visit visit){return visit.sell(this);
        }
        public void setPrice(int price) {this.price = price;}
    }
    public class Visit {
        /* 苹果计价 */
        public int sell(Apple apple){System.out.println("apple's price: ¥50");
            return 50;
        }
        /* 桔子计价 */
        public int sell(Orange orange){System.out.println("orange's price: ¥20");
            return 20;
        }
        /* 香蕉计价 */
        public int sell(Banana banana){System.out.println("banana's price: ¥30");
            return 30;
        }
        // 其它水果计价
        public int sell(Fruit fruit){System.out.println("other price: ¥10");
            return 10;
        }
    }
    public class VisitClient {private static Visit visit = new Visit();
        /* 库存 */
        private static List list = new ArrayList();
        static {list.add(StaticFactory.getFruitApple());
            list.add(StaticFactory.getFruitOrange());
            list.add(StaticFactory.getFruitBanana());
            list.add(StaticFactory.getFruitApple());
            list.add(StaticFactory.getFruitOrange());
        }
        private static int price() {
            int total = 0;
            for (Fruit fruit : list) {total += fruit.accept(visit);
            }
            System.out.println("总价值:" + total);
            return total;
        }
          public static void main(String[] args) {price();
        }

    访问者设计模式的关键是:不能直接使用 visit 对象直接调用 sell 方法将水果对象传递进去,因为直接传递进去由于方法重载的静态化问题,不会执行相应的方法,需要是使用 fruit 的 accept 方法才行。

    5. 访问者设计模式的使用场景

    通常在以下情况可以考虑使用访问者(Visitor)模式。

  • 对象结构相对稳定,但其操作算法经常变化的程序。
  • 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。
  • 对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作。
  • 阿里云 2 核 2G 服务器 3M 带宽 61 元 1 年,有高配

    腾讯云新客低至 82 元 / 年,老客户 99 元 / 年

    代金券:在阿里云专用满减优惠券

    正文完
    星哥玩云-微信公众号
    post-qrcode
     0
    星锅
    版权声明:本站原创文章,由 星锅 于2024-07-24发表,共计3651字。
    转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
    【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
    阿里云-最新活动爆款每日限量供应
    评论(没有评论)
    验证码
    【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

    星哥玩云

    星哥玩云
    星哥玩云
    分享互联网知识
    用户数
    4
    文章数
    19351
    评论数
    4
    阅读量
    7982300
    文章搜索
    热门文章
    星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

    星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

    星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
    星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

    星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

    星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
    我把用了20年的360安全卫士卸载了

    我把用了20年的360安全卫士卸载了

    我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
    再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

    再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

    再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
    飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

    飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

    飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
    阿里云CDN
    阿里云CDN-提高用户访问的响应速度和成功率
    随机文章
    如何免费使用强大的Nano Banana Pro?附赠邪修的用法

    如何免费使用强大的Nano Banana Pro?附赠邪修的用法

    如何免费使用强大的 Nano Banana Pro?附赠邪修的用法 前言 大家好,我是星哥,今天来介绍谷歌的 ...
    【开源神器】微信公众号内容单篇、批量下载软件

    【开源神器】微信公众号内容单篇、批量下载软件

    【开源神器】微信公众号内容单篇、批量下载软件 大家好,我是星哥,很多人都希望能高效地保存微信公众号的文章,用于...
    把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

    把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

    把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地 大家好,我是星哥,今天教大家在飞牛 NA...
    我把用了20年的360安全卫士卸载了

    我把用了20年的360安全卫士卸载了

    我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
    星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

    星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

    星哥带你玩飞牛 NAS-2:飞牛配置 RAID 磁盘阵列 前言 大家好,我是星哥之前星哥写了《星哥带你玩飞牛 ...

    免费图片视频管理工具让灵感库告别混乱

    一言一句话
    -「
    手气不错
    自己手撸一个AI智能体—跟创业大佬对话

    自己手撸一个AI智能体—跟创业大佬对话

    自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

    12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
    让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

    让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级

    让微信公众号成为 AI 智能体:从内容沉淀到智能问答的一次升级 大家好,我是星哥,之前写了一篇文章 自己手撸一...
    星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

    星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

    星哥带你玩飞牛 NAS-14:解锁公网自由!Lucky 功能工具安装使用保姆级教程 作为 NAS 玩家,咱们最...
    星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

    星哥带你玩飞牛NAS-16:飞牛云NAS换桌面,fndesk图标管理神器上线!

      星哥带你玩飞牛 NAS-16:飞牛云 NAS 换桌面,fndesk 图标管理神器上线! 引言 哈...