5

最近はデザインパターンを学んでいます。プログラミングデザインパターンに関するドキュメントはたくさんありますが、クロージャーデザインパターンに興味があります。

JavaとGroovyのデザインパターンに関するVenkatSubramaniamのプレゼンテーションを見つけ、自分の経験に基づいて、クロージャを含むこのプレゼンテーションのパターンとその他のパタ​​ーンを抽出しました。

実行方法

操作の前後に実行する必要がある操作のペア。

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ですが、同じ内容です):
クロージャーデザインパターン
クロージャーデザインパターン。Ruby版

4

3 に答える 3

11

クロージャとラムダ/匿名関数を混同していると思いますか?

クロージャーは、バインドされた変数を持つレキシカル コンテキストです。つまり、関数内から関数を定義すると、内側の関数は外側の関数で定義された変数にアクセスできます。この場合の「字句コンテキスト」は外部関数です。

ラムダは、変数の割り当てを持たない関数です。たとえばRubyでは、ブロックを関数に渡すことができ、関数はyieldキーワードのみを使用してブロックを内部で呼び出すことができます。JavaScript では、関数を定義して同時に引数として渡すことができます。あなたの例はすべてこれです。

ファーストクラス関数は、通常のオブジェクトのように渡すことができる関数です。それらを引数として関数呼び出しに渡し、それらへの参照を保持できます。これは 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

したがって、これはあなたの質問を混乱させます。閉鎖は言語機能であり、設計パターンではありません。これらの例で示したように、実装でクロージャー、ラムダ、モジュロ、コンストラクターなどを使用できる設計パターンはたくさんあります。それらはどれも古典的なデザインパターンではありませんが、私はそれらをそう呼ぶかどうかさえわかりません. たぶん私はそれらを砂糖と呼ぶでしょう。

Java はあらゆる種類のデザイン パターンを実装できますが、これらの機能はありません。この種の作業の多くは、完全に異なる言語機能であるインターフェースを使用して行われます。

于 2012-04-04T00:23:48.087 に答える
1

人々が言っ​​たように、これらは実際には「パターン」ではなく、Groovy にかなり固有のものですが、クロージャーの別の 2 つの用途は次のとおりです。

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
于 2012-04-04T07:42:52.913 に答える
1

クロージャーの設計パターンについて話すのは本当に意味がないという点で、他の回答に同意します(特に、あなたが本当にファーストクラスの関数について話しているように見える場合;))。あなたが本当に理解しようとしているポイントは、デザイン パターンを実装するときに、ファーストクラス関数、ラムダ、クロージャーなどのツールをどのように使用できるかということだと思います。これは Groovy に固有のものですが、次のページを参照すると役立つ場合があります: http://groovy.codehaus.org/Design+Patterns+with+Groovy

たとえば、「Loan my Resource Pattern」は、「Execute Around Method」パターンと非常によく似た方法で Closures を使用する方法を示しています。また、「Visitor Pattern」は Closures をうまく利用するものであり、含まれていません。あなたのリスト。

于 2012-04-10T12:08:13.283 に答える