Language agnostic 闭包在OOP中有什么用途?
PHP和.Net有闭包;我一直在想,在OOP和设计模式中使用闭包的例子有哪些,以及它们与纯OOP编程相比有哪些优势Language agnostic 闭包在OOP中有什么用途?,language-agnostic,oop,functional-programming,Language Agnostic,Oop,Functional Programming,PHP和.Net有闭包;我一直在想,在OOP和设计模式中使用闭包的例子有哪些,以及它们与纯OOP编程相比有哪些优势 作为澄清,这不是OOP与函数式编程,而是如何在OOP设计中最好地使用闭包。闭包如何适应工厂或观察者模式?例如,您可以使用哪些技巧来澄清设计并导致松散耦合。闭包对于事件处理非常有用。这个例子有点做作,但我认为它传达了一个想法: class FileOpener { public FileOpener(OpenFileTrigger trigger) {
作为澄清,这不是OOP与函数式编程,而是如何在OOP设计中最好地使用闭包。闭包如何适应工厂或观察者模式?例如,您可以使用哪些技巧来澄清设计并导致松散耦合。闭包对于事件处理非常有用。这个例子有点做作,但我认为它传达了一个想法:
class FileOpener
{
public FileOpener(OpenFileTrigger trigger)
{
trigger.FileOpenTriggered += (sender, args) => { this.Open(args.PathToFile); };
}
public void Open(string pathToFile)
{
//…
}
}
my file opener可以通过直接调用
instance.open(pathToFile)
打开文件,也可以由某个事件触发。如果我没有匿名函数+闭包,我就必须编写一个方法,该方法除了响应此事件之外没有其他用途。假设您希望提供一个能够创建任意数量的FileOpener
实例的类,但要遵循IoC原则,您不希望创建FileOpener
s的类实际知道如何操作(换句话说,您不希望new
s)。相反,您希望使用依赖项注入。但是,您只希望此类能够生成FileOpener
实例,而不仅仅是任何实例。以下是您可以做的:
class AppSetup
{
private IContainer BuildDiContainer()
{
// assume this builds a dependency injection container and registers the types you want to create
}
public void setup()
{
IContainer container = BuilDiContainer();
// create a function that uses the dependency injection container to create a `FileOpener` instance
Func<FileOpener> getFileOpener = () => { return container.Resolve<FileOpener>(); };
DependsOnFileOpener dofo = new DependsOnFileOpener(getFileOpener);
}
}
类AppSetup
{
私有IContainer BuildinContainer()
{
//假设这构建了一个依赖项注入容器,并注册了您想要创建的类型
}
公共作废设置()
{
IContainer容器=BuilDiContainer();
//创建一个使用依赖项注入容器创建“FileOpener”实例的函数
Func getFileOpener=()=>{return container.Resolve();};
DependsOnFileOpener dofo=新的DependsOnFileOpener(getFileOpener);
}
}
现在,您的类需要能够生成FileOpener实例。您可以使用依赖项注入为其提供此功能,同时保持松散耦合
class DependsOnFileOpener()
{
public DependesOnFileOpener(Func<FileOpener> getFileOpener)
{
// this class can create FileOpener instances any time it wants, without knowing where they come from
FileOpener f = getFileOpener();
}
}
class DependsOnFileOpener()
{
public DependesOnFileOpener(Func getFileOpener)
{
//此类可以随时创建FileOpener实例,而不知道它们来自何处
FileOpener f=getFileOpener();
}
}
任何具有闭包的语言都可以使用闭包进行蹦床,这是一种将递归重构为迭代的技术。这可以让您摆脱许多算法的幼稚实现遇到的“堆栈溢出”问题
蹦床是将闭包“反弹”回调用方的函数。闭包捕获了“剩余的工作”
例如,在Python中,可以定义递归累加器来对数组中的值求和:
testdata = range(0, 1000)
def accum(items):
if len(items) == 0:
return 0
elif len(items) == 1:
return items[0]
else:
return items[0] + accum(items[1:])
print "will blow up:", accum(testdata)
在我的机器上,当项目长度超过998时,这会导致堆栈溢出
同样的功能可以在蹦床式中使用闭包完成:
def accum2(items):
bounced = trampoline(items, 0)
while (callable(bounced)):
bounced = bounced()
return bounced
def trampoline(items, initval):
if len(items) == 0:
return initval
else:
return lambda: trampoline(items[1:], initval+items[0])
通过将递归转换为迭代,您不会破坏堆栈。闭包的特性是捕获计算本身的状态,而不是像递归那样捕获堆栈上的状态 这可能是社区维基。我也在想同样的事情。这个页面:有一个例子,但它可以很容易地重写没有闭包。巧妙的技巧!我想我以前从未见过这种情况。它在Python中最常见吗(这可以解释为什么我从未见过它)?它在Lisp世界中非常常见。在大多数Lisp实现中,它实际上是由编译器自动完成的(“尾部调用优化”)。但有时你必须手工操作,因为编译器只能识别特定配置中的模式。这在命令式语言中并不常见,但例如LEPL()使用蹦床来防止复杂的递归解析器溢出堆栈。