“封闭是穷人的对象,反之亦然” – 这是什么意思?
封闭是穷人的对象,反之亦然。
我在网上的很多 地方 ( 包括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()
匿名类实例中。
就这么多的糖,就像封闭物将匿名的物体藏在裙子下面一样。