惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

博客园 - FantasySoft

PHP菜鸟手记——如何解决无法装载动态链接库的问题 穿在身上的手机——M-Dress 团购之道——双赢才是核心 Demand Media——深谙中庸之道的新媒体 云中谁寄锦书来,盛大也! 《黑客》月刊中文版第一期正式发布,很给力!推荐围观! 比尔•盖茨:未来最好的教育来自互联网 CaptureDeviceManager.getDeviceList方法返回null对象问题探究 为了生活更美好,玩游戏吧! IronPython Tools——为IronPython度身定做的IDE 从博客园口水仗想到的 lambda与闭包 由XML Literal引发的思考 作为.NET程序员,您需要IronPython么? 静态注册BroadcastReceiver的注销问题 大道至简——Michael看iPad 波哥大BRT带来的启示 Timberland的企业社会责任 比尔•盖茨谈教育
三言两语话委托
FantasySoft · 2010-05-16 · via 博客园 - FantasySoft

几天前,Michael向大家推荐了刚发布的IronPython Tools for Visual Studio。不知道这个消息是否能够为大家学习IronPython注入少许动力呢?有了IDE的支持,Michael的学习热情也随之高涨了,把若干年前的随笔翻箱倒柜的看了个遍,那个感慨啊……对技术充满激情的岁月或许再也回不去了。咳,别感春悲秋嘛,这可是在写技术随笔哦!好吧,让我们回归正题。

在翻箱倒柜过程中,我看到了在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,那么您就可以思考一下封装性为啥是面向对象编程核心要素之一了。