OOP闭包有哪些用途?

时间:2010-09-30 17:06:02

标签: language-agnostic oop functional-programming

PHP和.Net有封闭;我一直想知道在OOP和设计模式中使用闭包的例子是什么,以及它们比纯OOP编程有什么优势。

作为澄清,这不是OOP与函数编程,而是如何在OOP设计中最好地使用闭包。闭包如何适用于工厂或观察者模式?例如,您可以采用哪些技巧来澄清设计并导致更松散的耦合。

3 个答案:

答案 0 :(得分:3)

闭包对事件处理很有用。这个例子有点人为,但我认为它传达了这个想法:

class FileOpener
{
     public FileOpener(OpenFileTrigger trigger)
     {
         trigger.FileOpenTriggered += (sender, args) => { this.Open(args.PathToFile); };
     }

     public void Open(string pathToFile) 
     { 
         //… 
     }
}

我的文件打开器可以通过直接调用instance.Open(pathToFile)打开文件,也可以通过某些事件触发。如果我没有匿名函数+闭包,我必须编写一个除响应此事件之外没有其他目的的方法。

答案 1 :(得分:3)

任何具有闭包的语言都可以将它们用于trampolining,这是一种将递归重构为迭代的技术。这可以让你摆脱许多算法的天真实现遇到的“堆栈溢出”问题。

蹦床是一种将一个闭包“弹回”到其来电者的功能。关闭捕获“剩下的工作”。

例如,在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])

通过将递归转换为迭代,您不会爆炸堆栈。闭包具有捕获计算状态的属性,而不是像递归一样捕获堆栈。

答案 2 :(得分:2)

假设您想要提供一个能够创建任意数量FileOpener实例的类,但遵循IoC原则,您不希望创建FileOpener的类实际知道如何操作所以(换句话说,你不想new他们)。相反,您希望使用依赖注入。但是,您只希望此类能够生成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);

    }
}

现在您的类需要能够创建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();
    }
}