一, 观察者模式的缺点

在之前的博文的介绍过观察者模式了.

观察者模式可以让多个观察者同时观察1个被观察者.

也就说被观察者可以1次过执行所有观察者的update()方法.

再通俗d来讲, 就是多个观察者的Update()方法交给被观察者来执行了.

观察者主要应用在Gui 界面的控件事件上,   例如按个按钮可以,令多个其他控件同时产生变化.

但是观察者模式有1个限制, 就是所有观察者类必须实现观察者(Observer)接口. 这个也是回调(callback)方法的1个实现.

现实项目中,  相当于一部分类是不能修改的, 很可能是Jar包发布或者你没有修改权限. (封闭--开放原则)

如果某个类没有实现观察者(Observer)接口,  那么有没有1个办法将这个类的某个方法也交给被观察者来执行呢?

二, 一个题目

假如当前有两个类,

1个是类A, 里面有1个无返回值无参方法a().

另1个是类B, 里面有1无返回值个无参方法b().

这两个类没有实现任何接口, 也不能被修改.

要求写1个类S,  这个类S类似与观察者模式的被观察者(Subject), 可以添加若干个类A或者类B的对象), 并可以通知它们执行自己的a()/b() 方法.

如果让类A和类B实现观察者(Observer)是很简单的.

难点就是它们都不能被修改.

三, C#的委托实现

C#有一种类叫delegate(委托), 他可以让方法(函数)的本身作为1个参数.

同样, 委托也可以是1个容器, 用于存放不同的对象的方法(前提是这些方法返回值和参数类型一样)

C#是这样实现的.

3.1 类A

class A{public void a(){Console.WriteLine("A.a()");}}

3.2 类B

  class B{public void b(){Console.WriteLine("B.b()");}}

3.3 类S

    public delegate void DelegateNoPra();class S{public DelegateNoPra dg;public void sNotify(){dg();}}

注意, 这里的委托(delegate void DelegateNoPra是定义在类S的外面的, 也就是跟类S同级.

然后在类S里构造1个DelegateNoPra的对象dg.

这里的dg相当于1个容器.

在sNotify()调用dg(); 相当于调用dg容器内所有的传入的方法.

3.4 客户端代码

  static void Main(string[] args){S s = new S();s.dg += new A().a;s.dg += new B().b;s.dg += new B().b;s.sNotify();Console.Read();}

客户端代码很容易看懂,

先实例化1个S对象

然后将1个A对象的方法a, 两个B对象的方法b 放入S对象的委托容器.

最终一次过被执行

输出:

A.a()
B.b()
B.b()

注意, 传入的方法必须是无参方法().   也就是将委托对象必须具有相同的参数类型和

如果有参数的方法怎么传入?

则必须再定义1个对应的delegate委托.

四, Java的反射实现

可以见到, C#的代码相当简洁.

而委托这种东西看起来比观察者模式更加方便.

但是现实上是先有观察者模式, 再有C#的委托的.

而且Java是没有委托(delegate)这种东西的, 但是java有反射, 利用java的反射特性也可以实现上面的功能.

4.1 类A

public class A {public void a(){System.out.println("A.a()");}
}

4.2 类B

public class B {public void b(){System.out.println("B.b()");}
}

4.3 类ObjMethod

这里稍稍想想, 到底如何将类A和类b的指定方法传入到另1个类呢?

其实我们可以把它拆分成两部分:

1. 传送对象本身(Object).

2. 传送方法的名字(String).

至于怎样把这两种不同类型的东西放入类S的容器?  方法有很多种,

这里我新建1个类ObjMethod, 把这两种东西封装在一起.

而且我是打算把它放入HashSet容器的, 所以重写了hashCode()和 equals()方法, 只要上面两个成员相等, 我们就认为是相同的两个对象.

代码:

public class ObjMethod {private Object obj;private String method;public ObjMethod(Object obj, String method){this.obj = obj;this.method = method;}public String getMethod() {return this.method;}public Object getObj() {return this.obj;}@Overridepublic boolean equals(Object o){ObjMethod m = (ObjMethod)o;return (this.getObj() == m.getObj()) && (this.getMethod().equals(m.getMethod()));}@Overridepublic int hashCode(){return this.getObj().hashCode() * this.getMethod().hashCode();}
}

4.4 类S

类S的Notify()方法要用到反射了.

其实步骤很简单:

1. 从HashSet获取对象Obj 和 方法名method

2. 利用反射特性获得Obj的类.

3. 利用Obj的类和方法名获得那个方法.

4. 执行这个方法.

import java.util.HashSet;
import java.util.Iterator;
import java.lang.reflect.Method;
public class S {private HashSet<ObjMethod> methodList = new HashSet<ObjMethod>();public void attach(Object obj, String method){this.methodList.add(new ObjMethod(obj,method));}public void detach(Object obj, String method){this.methodList.remove(new ObjMethod(obj,method));}public void sNotify(){if (this.methodList.isEmpty()){return;}Iterator<ObjMethod> it = this.methodList.iterator();while (it.hasNext()){ObjMethod m = (ObjMethod)it.next();Class<?> objClass = m.getObj().getClass(); //get the class of the objecttry{Method method = objClass.getMethod(m.getMethod(), new Class[]{}); //no any parametersmethod.invoke(m.getObj(),new Object[]{});//no parameters}catch(Exception e){e.printStackTrace();}}}}

4.5 客户端代码

     S s = new S();s.attach(new A(), "a");s.attach(new A(), "a");B b1 = new B();s.attach(b1, "b");s.sNotify();System.out.println("Step 2!");s.detach(b1,"b");s.sNotify();

代码也很容易看懂,

跟C#版本差不多. 只不过要把对象和方法名作为两个参数传入到类S对象的HashSet容器.

输出:

A.a()
B.b()
A.a()
Step 2!
A.a()
A.a()

上面的例子跟C#的委托一样, 同样要求传入的方法具有相同的参数类型.

当然, 再完善下甚至可以有一定限度地支持不同的参数类型.

五, 小结

利用Java的反射特性同样实现类似C#委托的功能, 当然代码看起来远远没有C#委托的简洁.

这是因为微软把很多底层的东西封装起来了, 更加方便程序猿的使用.

Java 利用反射实现C#的委托相关推荐

  1. Java利用反射封装DBUtil,mysql万能增删改查工具类,附源码

    Java利用反射封装DBUtil,mysql万能增删改查工具类,附源码 等有时间再慢慢写代码注释吧,先把源码放出来.文章最后有整个项目的压缩包. ps:拓展 Java 原生MySQL JDBC 插入后 ...

  2. JAVA利用反射模式调用实现类

    本文主讲,利用反射模式调用接口的实现类.抽象类的继承子类.下面请听屌丝一一道来 1.第一步在src下创建 com.newer.reflex包 2.在com.newer.reflex包下面建立 IRef ...

  3. Java利用反射动态加载类实战

    package com.web.common.utility.reflector; import java.io.Serializable; import java.lang.reflect.Cons ...

  4. Java利用反射调用有参构造方法返回对象

    public static void main(String[] args) {try {// 获取Class类Class<Person> cla = Person.class;// 打印 ...

  5. java判断对象无数据_java利用反射机制判断对象的属性是否为空以及获取和设置该属性的值...

    1.java利用反射机制判断对象的属性是否为空: Map validateMap = new LinkedHashMap(); validateMap.put("serial", ...

  6. java反射出抽象类的实现类_java利用反射模式调用实现类

    本文主讲,java利用反射模式调用接口的实现类.抽象类的继承子类.下面请听一一道来 1.第一步在src下创建com.newer.reflex包 2.在com.newer.reflex包下面建立IRef ...

  7. java设计模——反射的应用 (利用反射来去除if判断语句)

    利用反射来去除if判断语句 我的以前写的一个查分系统,就是部长让我写的那个,使用一个分发器(函数),他会根据传递进来的字符串参数调用不同的方. If("add".equalsIgn ...

  8. java反射是运行时,Java反射(三)在运行时利用反射分析对象

    在运行时利用反射分析对象,其实就是利用反射来获得或者设置类的域.举例如下: 有一个Student类: package testreflection; public class Student { pr ...

  9. java 反射 单例类_利用反射机制破坏单例模式

    简介 利用反射机制破坏了单例模式,这里以懒汉单例模式为例子进行操作. 之前利用反射也是改变了类中的private变量. 类中的private变量真的private么? 正常的单例模式的实现 这里采用了 ...

最新文章

  1. c语言编程输入年月日判断是否合法,C语言程序设计:输入年月日判断这是这一年中的第几天...
  2. redis的集群搭建
  3. 研究Mysql优化得出一些建设性的方案
  4. 通过init-connect + binlog 实现MySQL审计功能
  5. html 监控键盘,后台监控鼠标和键盘(可监听全局的鼠标以及键盘按键)
  6. seata 如何开启tcc事物_分布式事务Seata-TCC源码分析
  7. WGCNA分析,简单全面的最新教程(可以在线做了)
  8. 原来这就是比 ThreadLocal 更快的玩意
  9. php获取pid,在Shell脚本中获取指定进程的PID
  10. 从零基础入门Tensorflow2.0 ----六、28 深度可分离卷积神经网络
  11. oracle如何储存超长汉子_厦门到惠州整车运输超长超宽超重运输
  12. python爆破脚本_snmp爆破(python脚本)
  13. 关于matlab中数据拟合的一些函数polyfit()
  14. 工信部《物联网的十三五规划(2016-2020年)》
  15. 异数OS 织梦师-Xnign(四)-- 挑战100倍速Nginx,脚踩F5硬件负载均衡
  16. 推荐系统之从石器时代到青铜时代的演进史
  17. 正则表达式汇总--小鱼儿
  18. 前端性能优化:前端接口缓存方案
  19. 脚本中fi是什么意思
  20. python批量处理图片属性_python PIL 批量处理处理图片

热门文章

  1. 【python】排序算法的稳定性冒泡排序(画图详细讲解)
  2. Boost Part III. 函数对象与高级编程 Library 10. Lambda 用法
  3. 常见的钓鱼招式,可千万别入坑哦
  4. aliyun服务器安装git,g++
  5. 160个Crackme026之六段式注册码详解
  6. 【Alertmanager】腾讯企业邮箱配置
  7. 单源最短路径-Dijkstra(迪杰斯特拉算法)
  8. MySQL查询的进阶操作--联合查询
  9. MySQL查询的进阶操作--连接查询
  10. Spring boot的Spring MVC扩展功能