关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 算法设计 »23种设计模式之访问者模式

    23种设计模式之访问者模式

    2015-04-05 00:00:00 出处:ITJS
    分享

    定义:封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

    类型:行为类模式

    类图:

    23种设计模式(9):访问者模式

    访问者模式可能是行为类模式中最复杂的一种模式了,但是这不能成为我们不去掌握它的理由。我们首先来看一个简单的例子,代码如下:

    class A {
    	public void method1(){
    		System.out.println("我是A");
    	}
    
    	public void method2(B b){
    		b.showA(this);
    	}
    }
    
    class B {
    	public void showA(A a){
    		a.method1();
    	}
    }

    我们主要来看一下在类A中,方法method1和方法method2的区别在哪里,方法method1很简单,就是打印出一句“我是A”;方法method2稍微复杂一点,使用类B作为参数,并调用类B的showA方法。再来看一下类B的showA方法,showA方法使用类A作为参数,然后调用类A的method1方法,可以看到,method2方法绕来绕去,无非就是调用了一下自己的method1方法而已,它的运行结果应该也是“我是A”,分析完之后,我们来运行一下这两个方法,并看一下运行结果:

    public class Test {
    	public static void main(String[] args){
    		A a = new A();
    		a.method1();
    		a.method2(new B());
    	}
    }

    运行结果为:

    我是A
    我是A

    看懂了这个例子,就理解了访问者模式的90%,在例子中,对于类A来说,类B就是一个访问者。但是这个例子并不是访问者模式的全部,虽然直观,但是它的可扩展性比较差,下面我们就来说一下访问者模式的通用实现,通过类图可以看到,在访问者模式中,主要包括下面几个角色:

    抽象访问者:抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是visit方法中的参数定义哪些对象是可以被访问的。 访问者:实现抽象访问者所声明的方法,它影响到访问者访问到一个类后该干什么,要做什么事情。 抽象元素类:接口或者抽象类,声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的。抽象元素一般有两类方法,一部分是本身的业务逻辑,另外就是允许接收哪类访问者来访问。 元素类:实现抽象元素类所声明的accept方法,通常都是visitor.visit(this),基本上已经形成一种定式了。 结构对象:一个元素的容器,一般包含一个容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中一般很少抽象出这个角色。

    访问者模式的通用代码实现

    abstract class Element {
    	public abstract void accept(IVisitor visitor);
    	public abstract void doSomething();
    }
    
    interface IVisitor {
    	public void visit(ConcreteElement1 el1);
    	public void visit(ConcreteElement2 el2);
    }
    
    class ConcreteElement1 extends Element {
    	public void doSomething(){
    		System.out.println("这是元素1");
    	}
    
    	public void accept(IVisitor visitor) {
    		visitor.visit(this);
    	}
    }
    
    class ConcreteElement2 extends Element {
    	public void doSomething(){
    		System.out.println("这是元素2");
    	}
    
    	public void accept(IVisitor visitor) {
    		visitor.visit(this);
    	}
    }
    class Visitor implements IVisitor {
    
    	public void visit(ConcreteElement1 el1) {
    		el1.doSomething();
    	}
    
    	public void visit(ConcreteElement2 el2) {
    		el2.doSomething();
    	}
    }
    
    class ObjectStruture {
    	public static List<Element> getList(){
    		List<Element> list = new ArrayList<Element>();
    		Random ran = new Random();
    		for(int i=0; i<10; i++){
    			int a = ran.nextInt(100);
    			if(a>50){
    				list.add(new ConcreteElement1());
    			}else{
    				list.add(new ConcreteElement2());
    			}
    		}
    		return list;
    	}
    }
    
    public class Client {
    	public static void main(String[] args){
    		List<Element> list = ObjectStruture.getList();
    		for(Element e: list){
    			e.accept(new Visitor());
    		}
    	}
    }

    访问者模式的优点

    符合单一职责原则:凡是适用访问者模式的场景中,元素类中需要封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作,使用访问者模式一方面符合单一职责原则,另一方面,因为被封装的操作通常来说都是易变的,因此当发生变化时,就可以在不改变元素类本身的前提下,实现对变化部分的扩展。 扩展性良好:元素类可以通过接受不同的访问者来实现对不同操作的扩展。

    访问者模式的适用场景

    如果一个对象中存在着一些与本对象不相干(或者关系较弱)的操作,为了避免这些操作污染这个对象,则可以使用访问者模式来把这些操作封装到访问者中去。

    如果一组对象中,存在着相似的操作,为了避免出现大量重复的代码,也可以将这些重复的操作封装到访问者中去。

    但是,访问者模式并不是那么完美,它也有着致命的缺陷:增加新的元素类比较困难。通过访问者模式的代码可以看到,在访问者类中,每一个元素类都有它对应的处理方法,也就是说,每增加一个元素类都需要修改访问者类(也包括访问者类的子类或者实现类),修改起来相当麻烦。也就是说,在元素类数目不确定的情况下,应该慎用访问者模式。因此,访问者模式比较适用于对已有功能的重构,比如说,一个项目的基本功能已经确定下来,元素类的数据已经基本确定下来不会变了,会变的只是这些元素内的相关操作,这时候,我们可以使用访问者模式对原有的代码进行重构一遍,这样一来,就可以在不修改各个元素类的情况下,对原有功能进行修改。

    总结

    正如《设计模式》的作者GoF对访问者模式的描述:大多数情况下,你并需要使用访问者模式,但是当你一旦需要使用它时,那你就是真的需要它了。当然这只是针对真正的大牛而言。在现实情况下(至少是我所处的环境当中),很多人往往沉迷于设计模式,他们使用一种设计模式时,从来不去认真考虑所使用的模式是否适合这种场景,而往往只是想展示一下自己对面向对象设计的驾驭能力。编程时有这种心理,往往会发生滥用设计模式的情况。因此,在学习设计模式时,一定要理解模式的适用性。必须做到使用一种模式是因为了解它的优点,不使用一种模式是因为了解它的弊端;而不是使用一种模式是因为不了解它的弊端,不使用一种模式是因为不了解它的优点。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。