`

访问者模式进阶(三)

 
阅读更多
    这一篇讲述一下如何用反射改造访问者模式,使之在增加具体元素的时候也符合“开放-封闭”原则(OCP)。为了理解的连贯性继续采用之前的男人-女人的例子。
这是既定访问者的类图:





在(二)在介绍过,既定访问者模式增加具体元素之所以如此困难是因为访问者与具体元素(被访问者)的互相依赖,必须去除这这一层的依赖关系。
请看如何用反射来改变这一层依赖关系:
import java.lang.reflect.Method;

public abstract class ReflectionVisitor  {
	public void visit(Person person) {
		// 判断是否是null
		if (person == null) {
			throw new NullPointerException("大哥,Person不能为空啊!");
		}
		// 组装class数组,即调用动态方法的时候参数的类型
		Class[] classes = new Class[] { person.getClass() };
		// 组装与class数组相对应的值
		Object[] objects = new Object[] { person };
		try {
			// 查找方法
			Method m = getClass().getMethod("visit", classes);
			// 调用该方法
			m.invoke(this, objects);
		} catch (NoSuchMethodException e) {
			// 没有找到相应的方法
			System.out.println("在"+getClass().getName()+"中,你没有实现" + person.getClass().getName() + "的visit方法");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


现在抽象访问者不再是一个接口,而是一个抽象类,为了方便理解把它叫做ReflectionVisitor,里面退化到只有一个visit方法,参数是Person类型,也就是抽象访问者原来依赖于各个具体元素的关系被抽象成只依赖于具体元素的接口,这样当增加新的具体元素,抽象访问者就不需要因为增加对应新元素的visit方法而重新编译!

具体元素的接口与具体元素
基本没有变化,参数类型从Visitor变成ReflectionVisitor
public interface Person {     
     void accept(ReflectionVisitor visitor);
}

public class Man implements Person{

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

public class Woman implements Person{

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


具体访问者,也几乎没有变化,不过从实现Visitor接口变成继承ReflectionVisitor抽象类
//成功时Man与Woman的不同表现
public class Success extends ReflectionVisitor{

	public void visit(Man man) {
		System.out.println("当男人成功时,背后多半有一个伟大的女人");
	}

	public void visit(Woman girl) {
		System.out.println("当女人成功时,背后大多有一个不成功的男人");
	}
}

//恋爱时Man与Woman的不同表现
public class Love extends ReflectionVisitor{

	public void visit(Man man) {
		System.out.println("当男人恋爱时,凡事不懂也装懂");
	}

	public void visit(Woman girl) {
		System.out.println("当女人恋爱时,遇事懂也装不懂");
	}
}


ObjectStructure类与客户端测试代码
import java.util.*;

public class ObjectStructure {
    private List<Person> elements = new ArrayList<Person>();

    public void attach(Person element){
    	elements.add(element);
    }
    
    public void detach(Person element){
    	elements.remove(elements);
    }
    
    //遍历各种具体元素并执行他们的accept方法

    public void display(ReflectionVisitor visitor){
    	for(Person p:elements){
    		p.accept(visitor);
    	}
    }
}

public class Client {
      public static void main(String[] args) {
		ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure
		//实例化具体元素
		o.attach(new Man());  
		o.attach(new Woman());

		//当成功时不同元素的不同反映
		ReflectionVisitor success = new Success();          
		o.display(success);
		
		//当恋爱时的不同反映
		ReflectionVisitor amativeness = new Love();         
		o.display(amativeness);
		

	}
}

结果显示:
当男人成功时,背后多半有一个伟大的女人
当女人成功时,背后大多有一个不成功的男人
当男人恋爱时,凡事不懂也装懂
当女人恋爱时,遇事懂也装不懂


现在增加一个具体元素(被访问者)
public class Bruce implements Person {

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


修改一下客户端测试代码:
public class Client {
      public static void main(String[] args) {
		ObjectStructure o = new ObjectStructure();  //依赖于ObjectStructure
		//实例化具体元素
		o.attach(new Man());  
		o.attach(new Woman());
//		o.attach(new Bruce());
		//当成功时不同元素的不同反映
		ReflectionVisitor success = new Success();          
		o.display(success);
		
		//当恋爱时的不同反映
		ReflectionVisitor amativeness = new Love();         
		o.display(amativeness);
		
		//当失败时的不同反映
//		ReflectionVisitor fail = new Fail_Reflection();
//		o.display(fail);
	}
}

结果显示:
当男人成功时,背后多半有一个伟大的女人
当女人成功时,背后大多有一个不成功的男人
在visitor.reflection4.Success中,你没有实现visitor.reflection4.Bruce的visit方法
当男人恋爱时,凡事不懂也装懂
当女人恋爱时,遇事懂也装不懂
在visitor.reflection4.Love中,你没有实现visitor.reflection4.Bruce的visit方法


其实抽象访问者中的visit方法就是通过反射去查找每一个具体访问者中所实现的对各个具体元素的visit方法,然后捕捉NoSuchMethodException的异常。这样的好处就是你可以自由选择某种具体访问者对某种具体元素(被访问者)visit方法的实现,增加了灵活性。而且增加一个新具体元素时,再也不需要重新编译抽象访问者与所有具体访问者。从而达到部分的“开放-封闭”。当然,你要增加某种具体访问者的visit方法时,还需要去修改具体访问者的类。但这比修改所有访问者and重新编译要好得多。缺点就是,从实现Visitor接口变成了继承ReflectionVisitor抽象类~~~~~~

反射用在这个例子上有点乏味,迟下结合组合模式讲可能会更加恰当。
  • 大小: 50 KB
分享到:
评论

相关推荐

    java进阶必看书籍

    包括创建型模式(如单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式)、结构型模式(如适配器模式、装饰器模式、代理模式、桥接...访问者模式、责任链模式、命令模式、备忘录模式、状态模式和解释器模式)...

    LUA进阶源代码欣赏

    源代码中可能包含一些LUA特有的设计模式,如单例模式、观察者模式等,通过这些模式,开发者可以编写出更加优雅和可维护的代码。 总的来说,"LUA进阶源代码欣赏"是一个全面了解和提升LUA编程技巧的宝贵资源。通过...

    Java进阶之设计模式内含源码以及说明书可以自己运行复现.zip

    行为型设计模式,观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。在Java中,java.util.Observable和java.util.Observer接口就是实现这一模式...

    C++进阶(语法篇)

    设计模式则是面向对象软件工程中用于解决特定问题的一般性模板,它包含了多个经典模式如工厂模式、单例模式、策略模式、观察者模式、适配器模式等,这些模式在C++编程实践中经常被应用。 通过本文对C++进阶语法的...

    进阶篇.pdf

    行为型设计模式如模板方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访问者模式,主要处理对象间的交互和行为。 单例模式有多种实现方式,...

    stm32进阶实验应用

    进阶实验可能会涉及GPIO的模拟I/O、上下拉电阻配置、中断触发模式设置等,以及使用GPIO实现简单的通信协议,如I2C或SPI。 3. **ADC与DAC**:STM32内置了模拟到数字转换器(ADC)和数字到模拟转换器(DAC),使得它...

    java中级进阶高级23种设计模式详细介绍+代码详解PPT模板.pptx

    21. 访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 22. 中介者模式:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要...

    C++二十三种设计模式.pdf

    17. **访问者模式**:访问者模式表示一个作用于某对象结构中的各元素的操作,它可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 18. **状态模式**:状态模式允许对象在其内部状态改变时改变其行为,...

    重塑java基础高级进阶资源分享

    - **观察者模式**:当对象的状态改变时,所有依赖于它的对象都会得到通知并被自动更新。 #### 5. 高级框架和技术 - **Spring框架**:提供了一种轻量级的DI容器,简化了Java EE应用程序开发。 - **Hibernate**:是一...

    C++二十三种设计模式

    如策略模式(Strategy)、模板方法模式(Template Method)、观察者模式(Observer)、迭代器模式(Iterator)、命令模式(Command)、备忘录模式(Memento)、状态模式(State)、访问者模式(Visitor)、职责链...

    stm32基础及进阶学习

    这个压缩包文件提供的是关于STM32的基础和进阶学习资料,包括初级篇、中级篇和系统篇,总计3本书,共计334页,旨在帮助学习者全面了解并掌握STM32的使用。 《零死角玩转STM32+初级篇》(131页,4.3M)是入门STM32的...

    2011.06 - Java语言程序设计-进阶篇(原书第8版

    进阶篇可能会涉及一些Java中常用的模式,例如单例模式、工厂模式、观察者模式等。 10. 开发工具和环境:最后,进阶篇也可能简要介绍Java开发中常用的一些工具和环境,如集成开发环境(IDEs)、版本控制(如Git)...

    Java进阶编程(经典网帖合集)

    10. **设计模式**:学习和掌握常见的设计模式,如单例、工厂、观察者、装饰者、策略、代理等,能够提升代码的可复用性和可维护性。 11. **注解(Annotation)**:注解是Java提供的一种元数据,用于提供编译时和运行...

    前端全栈进阶 Nextjs打造跨框架SaaS应用

    ### 前端全栈进阶Next.js打造跨框架SaaS应用 #### 一、Next.js框架概述 Next.js是一个基于React的轻量级框架,主要用于构建高性能的应用程序。它在React的基础上添加了一系列强大的功能,如服务器端渲染(SSR)、...

    Java设计模式

    设计模式可以分为三大类:创建型模式(如工厂模式、抽象工厂模式、建造者模式、单例模式和原型模式),结构型模式(如适配器模式、装饰器模式、代理模式、桥接模式、组合模式、外观模式和享元模式),行为型模式(如...

    Istio 服务网格进阶实战.pdf

    总结起来,Istio服务网格进阶实战主要涵盖了Istio的概念原理、服务网格的架构与实现模式、数据平面与控制平面的配置与管理、流量管理基础概念以及安全、监控和多集群部署等多个方面。随着微服务架构在云计算时代的...

    Tableau数据分析可视化高手进阶

    此外,还将学习如何使用LOD(Level of Detail)表达式进行复杂的数据聚合和细分分析,这对于理解和展示大规模数据集的模式至关重要。 在数据可视化方面,课程将教授如何选择合适的图表类型,如条形图、折线图、散点...

    设计模式源码

    包括责任链模式(Chain of Responsibility)、命令模式(Command)、解释器模式(Interpreter)、迭代器模式(Iterator)、中介者模式(Mediator)...Strategy)、模板方法模式(Template Method)和访问者模式(Visitor)...

    perl语言进阶

    类型符号表允许开发者访问变量和子程序的内部属性;而符号表则是Perl用来存储程序中所有标识符的地方。了解这两个概念有助于深入理解Perl的工作原理,并能够更好地控制和调试程序。 #### 四、子程序引用与闭包...

Global site tag (gtag.js) - Google Analytics