【问题标题】:Closure Design Patterns闭包设计模式
【发布时间】:2012-04-17 16:29:22
【问题描述】:

这些天我正在学习设计模式。有很多关于编程设计模式的文档,但我对闭包设计模式很感兴趣。

我找到了 Venkat Subramaniam 关于Design Patterns in Java and Groovy 的演示文稿,并根据我自己的经验提取了该演示文稿中涉及闭包的一些模式和其他模式。

执行环绕方法

操作前后需要执行的一对操作。

def operations(closure) {
    println "Open"
    closure()
    println "Close"
}

operations { println "Operation" }

===> Open
===> Operation
===> Close

可插拔行为

指定对象在运行时的行为。

def selectValues(number, closure) {
    def list = []
    1.upto(number) {
        if (closure(it)) list << it
    }
    return list
}

assert [2, 4, 6, 8, 10] == selectValues(10) { it % 2 == 0 }  // even
assert [1, 3, 5, 7, 9]  == selectValues(10) { it % 2 != 0 }  // odd

迭代器模式

允许顺序访问元素。

def listNumbers(closure) {
    (0..5).each { closure it }
}

listNumbers {
    if (it < 3) println "$it is a little number"
    else println "$it is a big number"
}

===> 0 is a little number
===> 1 is a little number
===> 2 is a little number
===> 3 is a big number
===> 4 is a big number
===> 5 is a big number

动态条件执行

创建并执行条件操作。

def greet(user, successClosure, failClosure) {
    if (isAdmin(user)) successClosure()
    else failClosure()
}

greet(user, { println "Hi Admin!" }, { println "Hello User" })

我想了解更多闭包设计模式。有没有关于这个话题的参考?随意用你最喜欢的编程语言编写一个新模式。


更新

我写了一篇关于这个主题的帖子(Groovy 和 Ruby,但内容相同):
Closure Design Patterns
Closure Design Patterns. Ruby Edition

【问题讨论】:

  • 如果必须命名某些东西,我通常会发现其中有太多的想法。 A closure just represents an invocable context(例如函数)带有一组 [非空] 绑定变量。没什么特别的。另请注意,闭包是一种特殊类型的 lambda 或匿名函数(绑定一个或多个变量的函数):selectValues 中可能没有闭包(嗯, 任何上面的例子),例如。无论如何......我并没有真正“得到”这个问题。
  • (实际上,闭包也不必是匿名的:它们正好适合这样的模式。)
  • 好问题阿图罗:)。我想有些答案不会像您希望的那样与语言无关,因为在诸如 Groovy、JavaScript 或 Ruby 之类的语言中可以做的事情在 Java 中没有太大意义。 “但是 Java 没有闭包!”你可能会说……嗯,它有词法范围(匿名)类,你可以用它做所有可以用闭包做的事情。但这样做太麻烦了,只需重复“过滤器”或“映射”的逻辑,一次又一次地编写相同的“for each”循环会更容易。
  • @pst 你对什么是闭包是正确的。 Arturo 的问题可能是 Groovy 语言使用术语“闭包”来指代任何匿名函数。它们是Closure 类的一个实例。我认为类似于 Ruby 的Procs。顺便说一句,我也同意将函数的一些常见用途命名为一等对象并没有多大价值。我会坚持说,期望另一个函数作为参数或返回函数的函数是“高阶函数”,仅此而已。但我也认为尝试找到这些模式很酷:)
  • @Arturo 在你做任何事情之前,我会阅读一些关于设计模式这个术语的历史。这是一个有趣的问题,许多老前辈(相对于大多数这些概念的发明,并没有那么老)只会想起 Gang of Four 模式,而其他人可能会想到 JavaEE 模式。我认为您的示例有更新的术语,例如 sugarexpressive power (在维基百科上查找,它简要讨论了高阶函数和闭包) .也许你应该问一个关于 Groovy 的问题 =D

标签: design-patterns language-agnostic groovy closures


【解决方案1】:

我认为您将闭包与 lambda/匿名函数混淆了?

Closure 是具有绑定变量的词法上下文。简而言之,如果您从函数内部定义函数,则内部函数可以访问外部函数中定义的变量。在这种情况下,“词法上下文”是外部函数。

Lambdas 是没有变量赋值的函数。例如,在 Ruby 中,您可以将块传递给函数,而函数可以仅使用 yield 关键字在内部调用它。在 JavaScript 中,您可以定义一个函数并同时将其作为参数传递。你的例子就是这些。

First-class functions 是另一回事,它们是可以像常规对象一样传递的函数。您可以将它们作为参数传递给函数调用并保存对它们的引用。这就像 Ruby 的Proc。在 JS 中,所有的函数都是一等的,所有的函数都是对象。

在 JavaScript 中,我们可以用一个愚蠢的例子来说明所有 3 个:

function foo(func) {
  func();
}
var bar = function() {    // bar is a first-class function
  var i = 5;
  foo(function() {        // this is the anonymous function (lambda)
    console.log(i);       // i is the closure-bound variable
  });
}
foo(bar);   // Prints 5

因此,这使您的问题变得混乱。闭包是一种语言特性,而不是一种设计模式。有很多设计模式的实现可以使用闭包或lambda或模或构造函数或其他任何东西,正如您通过这些示例向自己展示的那样。虽然这些都不是classical design patterns,所以我不确定我什至会这样称呼它们。也许我会称它们为糖。

Java 可以实现各种设计模式,但没有这些特性。很多这类事情都是通过接口完成的,这是一种完全不同的语言特性。

【讨论】:

    【解决方案2】:

    正如人们所说,这些并不是真正的“模式”,并且是特定于 Groovy 的,但是闭包的另外两个用途是:

    1。可组合性

    def sum    = { Collection a -> a.sum() }
    def first2 = { Collection a -> a.take( 2 ) }
    
    def take2andAdd = sum << first2
    
    println take2andAdd( [ 1, 2, 3, 4 ] ) // Prints 3
    

    2。咖喱

    def add = { a, b -> a + b }
    def add2 = add.curry( 2 )
    
    println add2( 3 ) // Prints 5
    

    当然,这些可以组合:

    def square = { a -> a * a }
    def add = { a, b -> a + b }
    def add2 = add.curry( 2 )
    
    def add2andSquare = square << add2
    
    println add2andSquare( 3 ) // prints 25
    

    【讨论】:

      【解决方案3】:

      我同意其他回答,因为谈论闭包设计模式并没有真正的意义(尤其是当您似乎真的在谈论一流的函数时;))。我认为您真正想要了解的重点是在实现设计模式时如何使用诸如一流函数、lambda 和闭包之类的工具。尽管它特定于 Groovy,但您可能会发现查看此页面很有用:http://groovy.codehaus.org/Design+Patterns+with+Groovy

      例如,“借用我的资源模式”展示了如何以与“执行周围方法”模式非常相似的方式使用闭包,而“访问者模式”也很好地利用了闭包并且不是t 包含在您的列表中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-27
        • 2010-10-11
        • 1970-01-01
        • 2011-01-20
        • 1970-01-01
        • 1970-01-01
        • 2011-08-02
        相关资源
        最近更新 更多