Java 利用反射实现C#的委托
一, 觀察者模式的缺點
在之前的博文的介紹過觀察者模式了.
觀察者模式可以讓多個觀察者同時觀察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()方法, 只要上面兩個成員相等, 我們就認為是相同的兩個對象.
代碼:
4.4 類S
類S的Notify()方法要用到反射了.
其實步驟很簡單:
1. 從HashSet獲取對象Obj 和 方法名method
2. 利用反射特性獲得Obj的類.
3. 利用Obj的類和方法名獲得那個方法.
4. 執行這個方法.
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#的委托的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 回调(callback)函数简
- 下一篇: Java xml 工具 JDOM 使用