Java 利用反射实现C#的委托
2015-01-03 21:37
375 查看
一, 观察者模式的缺点
在之前的博文的介绍过观察者模式了.观察者模式可以让多个观察者同时观察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; } @Override public boolean equals(Object o){ ObjMethod m = (ObjMethod)o; return (this.getObj() == m.getObj()) && (this.getMethod().equals(m.getMethod())); } @Override public 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 object try{ Method method = objClass.getMethod(m.getMethod(), new Class[]{}); //no any parameters method.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的反射与代理实现IOC模式
- C#利用反射实现(js)Eval,asp(Execute)功能 动态执行类库中的函数
- c#利用反射+特性实现简单的实体映射数据库操作类实现自动增删改查(一)
- 利用JAVA的动态属性之反射原理实现一个简单AOP容器 - AOP的实现原理分析
- 利用java反射实现Java Bean 类型转换
- 利用java的反射原理实现数据注入功能
- c#利用反射+特性实现简单的实体映射数据库操作类实现自动增删改查(三)带源码写好的持久层
- C#利用反射技术实现winform界面动态存储
- C# :实现水印与图片合成,并利用Graphics 压缩图像质量 , (委托实现listBox的动态添加提示)
- 利用Java的反射与代理实现IOC模式
- 利用Java的反射与代理机制实现IOC
- 利用Java的反射与代理实现AOP(推荐!!!)
- 利用Java的反射与代理机制实现AOP
- C#中利用委托实现多线程跨线程操作
- C#利用委托实现窗体间的值传递
- JAVA利用反射模式调用实现类
- 利用Java的反射与代理机制实现AOP
- 利用Java的反射与代理实现AOP(转载)
- C#中利用委托实现多线程跨线程操作
- C#动态执行类库中的函数:利用反射实现(js)Eval,asp(Execute)功能