“封闭是穷人的对象,反之亦然” – 这是什么意思?

封闭是穷人的对象,反之亦然。

我在网上的很多 地方 ( 包括SO )看过这个声明,但是我不太明白它的含义。 有人能解释一下究竟是什么意思吗?

如果可能的话,请在答案中包含例子。

重点是闭包和对象实现相同的目标:将数据和/或function封装在单个逻辑单元中。

例如,你可以创build一个像这样代表一条狗的Python类:

class Dog(object): def __init__(self): self.breed = "Beagle" self.height = 12 self.weight = 15 self.age = 1 def feed(self, amount): self.weight += amount / 5.0 def grow(self): self.weight += 2 self.height += .25 def bark(self): print "Bark!" 

然后我将这个类实例化为一个对象

 >>> Shaggy = Dog() 

Shaggy对象具有内置的数据和function。当我调用Shaggy.feed(5) ,他获得了一磅。 该磅被存储在作为对象的属性存储的variables中,这或多或less意味着它在对象内部范围内。

如果我编写了一些JavaScript,我会做类似的事情:

 var Shaggy = function() { var breed = "Beagle"; var height = 12; var weight = 15; var age = 1; return { feed : function(){ weight += amount / 5.0; }, grow : function(){ weight += 2; height += .25; }, bark : function(){ window.alert("Bark!"); }, stats : function(){ window.alert(breed "," height "," weight "," age); } } }(); 

在这里,我不是在一个对象中创build一个范围,而是在一个函数中创build一个范围,然后调用该函数。 该函数返回由一些函数组成的JavaScript对象。 因为这些函数访问在本地作用域中分配的数据,所以不会回收内存,允许您通过闭包提供的接口继续使用它们。

对象是穷人的closures。

考虑Java。 Java是一种面向对象的编程语言,没有真正的词法closures的语言级支持。 作为解决方法,Java程序员使用匿名内部类来closures词法作用域中可用的variables(假设它们是final )。 从这个意义上说,物体是穷人的封闭物。

封闭是穷人的对象。

考虑一下Haskell。 Haskell是一种function语言,不支持真实对象的语言级别。 然而,他们可以使用闭包来模拟,正如Oleg Kiselyov和Ralf Lammel在这篇优秀论文中所描述的那样。 从这个意义上讲,封闭是穷人的对象。


如果你是来自面向对象的背景,那么你可能会发现对象的思维更加自然,因此可能认为它们比封闭更基本。 如果你来自FP背景,那么你可能会觉得封闭的思维更自然,因此可能认为它们是比物体更基本的概念。

这个故事的寓意是, 封闭物和对象是可以相互expression的想法,没有一个比另一个更基本 。 这就是所有正在审议的声明。

在哲学中,这被称为模型依赖现实主义 。

一个最简单的对象就是在这个状态下运行的状态和函数的集合。 closures也是一个状态和一个在该状态下运行的函数的集合。

比方说,我调用了一个callback函数。 在这个callback函数中,我需要对函数调用之前已知的状态进行操作。 我可以创build一个体现这个状态的对象(“fields”)并且包含一个作为callback函数执行的成员函数(“method”)。 或者,我可以采取快速和容易(“穷人的”)路线,并创build一个封闭。

作为一个对象:

 class CallbackState{ object state; public CallbackState(object state){this.state = state;} public void Callback(){ // do something with state } } void Foo(){ object state = GenerateState(); CallbackState callback = new CallbackState(state); PerformOperation(callback.Callback); } 

这是伪C#,但在概念上与其他OO语言类似。 正如你所看到的,callback类涉及相当数量的样板来pipe理状态。 这将使用封闭更简单:

 void Foo(){ object state = GenerateState(); PerformOperation(()=>{/*do something with state*/}); } 

这是一个lambda(同样,在C#语法中,这个概念在支持闭包的其他语言中是相似的),它给了我们类的所有function,而不必编写,使用和维护一个单独的类。

你也会听到这样的推论:“对象是一个穷人的封闭”。 如果我不能或者不会利用closures,那么我就不得不用物体来做他们的工作,就像我的第一个例子。 尽pipe对象提供了更多的function,但由于前面已经提到的原因,closures通常是封闭工作的更好的select。

因此,一个没有东西的穷人往往可以通过closures来完成工作,而一个没有closures的穷人可以使用对象来完成工作。 一个富有的人每个工作都有合适的人选。

编辑:问题的标题不包括“反之亦然”,所以我会尽量不要承担提问者的意图。

两个共同的阵营是function与命令式语言。 这两种工具都可以通过不同的方式以不同的方式完成类似的任务。

封闭是穷人的对象。

对象是穷人的closures。

个别而言,每个陈述通常意味着作者有一定的偏见,通常根据他们对一种语言或一类语言的舒适程度,而另一种语言的不舒适程度。 如果不是偏见,他们可能会被一个环境或另一个环境所约束。 我读过的作者说,这种东西通常是狂热的,纯粹主义的或语言的宗教types。 如果可能,我避免使用语言宗教types。

封闭是穷人的对象。 对象是穷人的closures。

这个作者是一个“实用主义者”,也很聪明。 这意味着作者对这两种观点都表示赞赏,并且赞赏他们在概念上是一致的。 这是我的同类。

“对象是一个穷人的closures”不仅仅是一些理论上的对等的陈述 – 这是一个常见的Java成语。 使用匿名类来包装一个捕获当前状态的函数是很常见的。 以下是它的使用方法:

 public void foo() { final String message = "Hey ma, I'm closed over!"; SwingUtilities.invokeLater(new Runnable() { public void run() { System.out.println(message); } }); } 

这甚至看起来很像使用另一种语言的闭包的等效代码。 例如,使用Objective-C块(因为Objective-C与Java非常相似):

 void foo() { NSString *message = @"Hey ma, I'm closed over!"; [[NSOperationQueue currentQueue] addOperationWithBlock:^{ printf("%s\n", [message UTF8String]); }]; } 

唯一真正的区别是,该function被封装在Java版本的new Runnable()匿名类实例中。

就这么多的糖,就像封闭物将匿名的物体藏在裙子下面一样。