委托,事件,动态代理,函数指针

在翻箱倒柜过程中,我看到了在2007年2月发表的《不谈模式,只谈实现》 。这是受到Justin一篇美文 的启发,我所写的当年唯一一篇有关程序设计的文章。对于这篇随笔,老赵给我留下了这样的评论:

 

“这就是动态语言啊,相当于保留函数指针。
C#里面很像函数指针的是什么的呢?就是delegate。
而delegate的典型应用是什么呢?就是事件机制。
那么Java里的事件机制是怎么做到的呢?就是定义EventListener然后实现相应的方法。这就是和那个OO的Duck类似的实现了,一个Duck和一个EventListener在这个方面有些接近。
如果不熟悉Java的Event Listener的话也可以用传统的Observer模式来看,而且其实Event Listener等等,其实不就是用了Observer模式嘛。”

 

说实在话,由于自己水平有限,偶对这个评论并不能完全理解,特别是老赵提到了我并不是非常熟悉的delegate。到三年后的今天,偶再次阅读这条评论的 时候,不得不由衷赞叹:老赵的评论字字珠玑!对于偶这个Java开发者来说,委托(delegate)是一个相对陌生的概念,即便是动态代理 也并非委托在Java世界里的孪生兄弟。事实上,Java语言为什么能够如此流行,抛弃了难以驾驭的指针,降低了学习门槛 是重要原因之一。但是,没了指针,也直接导致无法使用函数指针,这让很多C++开发人员使用Java就等于丧失了大半功力。C#作为Java后来者,在灵活性和简单之间取得了良好的平衡点,譬如,在方法参数上,Java只能传值,而C#既可以传值也可以传引用 。对于函数指针,C#则创造了新的机制与之对应——那就是委托了。如果您和我一样,对委托了解得不够深入的话,建议您将JimmyZhang 的经典文章——《C# 中的委托和事件》 反复研读几遍,就会对委托有充分的了解了。如果您也和我一样,对为什么需要委托也心存疑虑的话,建议您阅读老赵的美文——《高阶函数、委托与匿名方法》 ,这也是一篇值得反复品味的文章。看了上述两篇文章之后,我们可以得出这样的结论:委托类型实现了强类型函数指针的功能,通过委托类型,我们可以将某个函数封装起来作为另外一个函数的参数 。这个特点在函数编程语言(譬如IronPython)中则不是什么新鲜事了,对照《C# 中的委托和事件》中的第一个完整的范例,使用IronPython实现之:

 

>>> def EnglishGreeting(name): ... print("Morning," + name) ... >>> def ChineseGreeting(name): ... print("早上好," + name) ... >>> def GreetPeople(name, MakeGreeting): ... MakeGreeting(name) ... >>> GreetPeople("Jimmy Zhang", EnglishGreeting) Morning,Jimmy Zhang >>> GreetPeople("张子阳", ChineseGreeting) 早上好,张子阳

由于IronPython是一门动态语言,并且支持函数编程范式,所以我们可以直接将函数(方法)作为参数传递给另外一个函数(方法)。而在C#中,要实现这一点就需要使用委托类型了。

接下来,既然C#创造了委托类型,那么它的应用又在哪呢?是的,正如老赵的评论所言,事件机制是委托最典型的应用 。有很多朋友都会觉得委托的使用有些多此一举,直接调用不就好了,那么兜兜转转干嘛呢?实际上,如果您希望直接调用也没啥问题,但是当需求改变的时候,您发现代码有无数的地方需要修改,那个时候就估计一个头两个大了。通过委托,我们可以更好地实现Observer模式,而这个模式定义了对象之间一对多的 依赖关系,当一个对象改变了状态,那么所依赖的多个对象就会收到通知并且更新状态。 要更好地了解Observer这个模式,除了《C# 中的委托和事件》中的讲解之外,仍旧是JimmyZhang的力作——《重温Observer模式--热水器·改》 。 文中给出了不使用委托实现Observer的方法,大家可以对比一下,繁简立现!看到文中IObservable接口的 Register(IObserver obj)和Unregister(IObserver obj)方法,大家会联想到什么?是的,就是在.NET事件机制的典型应用当中,经常出现的+=和-=操作符,它们的作用在于更改委托对象所引用的方法列 表。如果不使用委托,那么我们并不能直接对引用的方法列表进行操作,而要面向接口进行编程了。而对于IronPython来说,既然函数是一等公民,可以 作为方法的参数,那么通过list的append方法就能轻松操作引用的方法列表了。参照JimmyZhang的两篇文章,我们也可以使用 IronPython实现类似的热水器功能:

def makeAlarm(temperature): print("Alarm: " + str(temperature)) def showMsg(temperature): print("Display: " + str(temperature)) class Heater: def __init__(self): self.event = [] def boilWater(self): for i in range(1,100): self.temperature = i if self.temperature > 95: [m(self.temperature) for m in self.event] heater = Heater() heater.event.append(makeAlarm) heater.event.append(showMsg) heater.boilWater()

上述代码中的[m(self.temperature) for  m  in  self.event] 使用了IronPython强大的列表内涵特性,self.event是一个list,其中的元素就是makeAlarm和showMsg这两个函数。通 过m(self.temperature)就能够以self.temperature为参数调用上述两个函数了。大家是否觉得使用IronPython所 编写的代码会更加短小精悍呢?

综上所述,如果您不明白什么是委托,那么您可以把它看作强类型的函数指针;如果您不知道什么是函数指针,那么您可以把它 看作将函数(方法)作为参数传递的一种机制;如果您不了解为什么需要委托,那么您可以参考一下使用与不使用委托来实现Observer模式之间的区别;如 果您不知道为啥需要Observer模式,那么您可以进而了解一下Law of Demeter ;如果您仍然不知道为啥需要遵循Law of Demeter,那么您就可以思考一下封装性为啥是面向对象编程核心要素之一了。

 

Link: http://www.cnblogs.com/perhaps/archive/2010/05/16/1736804.html

你可能感兴趣的:(java,编程,list,C#,Class,语言)