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

推荐订阅源

P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
博客园_首页
宝玉的分享
宝玉的分享
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
量子位
T
Tailwind CSS Blog
雷峰网
雷峰网
Blog — PlanetScale
Blog — PlanetScale
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
月光博客
月光博客
罗磊的独立博客
F
Fortinet All Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
J
Java Code Geeks
V
V2EX
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Docker
阮一峰的网络日志
阮一峰的网络日志
I
InfoQ
Simon Willison's Weblog
Simon Willison's Weblog
D
DataBreaches.Net
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
I
Intezer
Scott Helme
Scott Helme
B
Blog
M
MIT News - Artificial intelligence
K
Kaspersky official blog
H
Help Net Security
V
Vulnerabilities – Threatpost
C
CXSECURITY Database RSS Feed - CXSecurity.com
Engineering at Meta
Engineering at Meta
博客园 - 【当耐特】
L
Lohrmann on Cybersecurity
P
Privacy & Cybersecurity Law Blog
Project Zero
Project Zero
The Hacker News
The Hacker News
B
Blog RSS Feed
T
Tor Project 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,那么您就可以思考一下封装性为啥是面向对象编程核心要素之一了。