2012-06-11 9 views
16

私はこのデザインの質問に対するすっきりした答えを得られませんでした。私は".NET Framework design guidelines"でも"C# programing guidelines"でも助けを見つけることができませんでした。 私は基本的に、ユーザーがこのように私のフレームワークにそのアルゴリズムを定義し、統合することができるようにAPIとしてパターンを露光する必要があります。代理人(ラムダ式)対インタフェースと抽象クラス

1)

// This what I provide 
public abstract class AbstractDoSomething{ 
    public abstract SomeThing DoSomething(); 
} 

ユーザーは、彼らは、この抽象クラスを実装する必要があります(私はそれを私の枠組みの中から呼び出して使用することができます)

2)

メソッドを実装する必要があります

私は、これはまた、デリゲートを使用してacheivedできることを発見した:

DoSomething do = new DoSomething() 
{ 
    Id="ThisIsMyID", 
    DoSomething = (() => new Something()) 
} 

質問

:この場合

public sealed class DoSomething{ 
    public String Id; 
    Func<SomeThing> DoSomething; 
} 

、ユーザーは、このようDoSomethingクラスを使用することができますこれらの2つのオプションのうちは、簡単で使いやすく、最も重要なのは、APIとして公開するための最もわかりやすいです。 の場合

EDIT:

の場合
MyFramework.AddDoSomething("DoSomethingIdentifier", new MyDoSomething()); 

:登録は次のように行われる登録がMyDoSomethingAbstractDoSomethingを拡張仮定(このようにして行われます:

MyFramework.AddDoSomething(new DoSomething()); 
+0

ユーザはフレームワークでAbstractDoSomethingsをどのように登録しますか? – dtb

+0

@dtb私の編集を参照してください(ビットも同様に修正) – GETah

答えて

15

これらの2つのオプションは、APIとして公開するのが最も簡単で使いやすく、最も重要なことはどれですか?

第1のものは、OOPの点でより「伝統的」であり、多くの開発者にとって理解しやすいものです。また、ユーザーがオブジェクトのライフタイムを管理できるという利点もあります(つまり、クラスにIDisposableを実装させ、シャットダウン時にインスタンスを破棄することができます)。また、将来のバージョンでも容易に拡張できます基本クラスに仮想メンバーを追加してもAPIが破られることはないため、下位互換性は損なわれません。最後に、これを自動的に作成するためにMEFのようなものを使用したい場合は、ユーザーの観点から「登録」のプロセスを単純化/削除することができます(サブクラスを作成して自動的に発見/使用されます)。

2番目はより機能的なアプローチであり、多くの点でより簡単です。これにより、ユーザーは既存のコードの変更を大幅に少なくしてAPIを実装できます。新しいタイプを作成する代わりに、必要な呼び出しをラムダでクロージャでラップするだけで済みます。

MyFramework.AddOperation("ThisIsMyID",() => DoFoo()); 

これは、それを作る:同じようにメソッドを使用する - としているあなたは、デリゲートを使用してのアプローチを取るつもりなら、私も、ユーザがクラスを作成することはないだろうということ

私の意見では、システムに操作を直接追加していることをもう少し明確にしています。また、パブリックAPI(DoSomething)に別のタイプを追加する必要がなくなり、APIも簡単になります。

+0

+1。ご回答有難うございます。 'Func'を自分のフレームワークに直接登録する問題は、将来その機能を拡張することができないことです(DoSomethingに振る舞いを追加できない) – GETah

+0

@GETah私の記事で述べたように、振る舞いを追加すると、おそらくクラスが良いでしょう。 (仮想メンバーの追加に関する文章を参照してください...)それは、IMOです。デリゲートの代わりにクラスを使用する主な利点です。 –

+0

わかりました。コメントしてくれてありがとう。 – GETah

6

私があれば、抽象クラス/インタフェースとなるだろう:doSomethingのが必要な

  • (doSomethingのの実装は、いくつかのプライベート/保護されたメソッドにsplitedできるように)
  • doSomethingのが通常
本当に大きいでしょう

場合、私は代表者となるだろう:

  • DoSomethi質問これらのタイプのほとんどのために典型的であるようにNGが(OnDoingSomething)
  • doSomethingのはオプションです(あなたがノーオペレーションデリゲートにそれをデフォルト)イベントとして
1

を扱うことができ、私は「それを言うでしょう依存する "。 :)

しかし、私は抽象クラスとラムダを使用する理由は本当に動作になると思います。通常、私はlambdaがコールバックタイプの機能として使用されていると思います。何か他のことが起こったときに何かカスタムが起こるようにしたいと思っています。私は、この私のクライアント側のコードで多くの操作を行います - サービスコール を作る - バック をいくつかのデータを取得する - 今、そのデータを処理するために、私のコールバックを呼び出しに応じ

あなたはラムダと同じことを行うことができます - を彼ら非常に特殊な状況に特化しており、ターゲットとしています。

抽象クラス(またはインターフェイス)を使用することは、クラスの動作がその周囲の環境によって駆動される場所に実際に来ることになります。何が起こっているのですか、私はどのクライアントを扱っていますか?これらの大きな質問は、一連の振る舞いを定義し、開発者(またはAPIの消費者)が自分の要件に基づいて独自の振る舞いを作成できるようにする必要があることを示唆しています。確かに、ラムダでも同じことができますが、開発するのがより複雑になり、ユーザーと明確にコミュニケーションするのがより複雑になると思います。

私はおおよその経験則を次のように推測しています: - 特定のコールバックまたは副作用のカスタマイズされた動作にlambdaを使用します。 - 抽象クラスまたはインタフェースを使用して、オブジェクト動作のカスタマイズ(または少なくともオブジェクトの主な動作の大部分)のためのメカニズムを提供します。

申し訳ありませんが、私はあなたに明確な定義を与えることはできませんが、これが役立つことを願っています。がんばろう!考慮すべき

1

いくつかのこと:

がどのように多くの異なる機能/代表者だらけの上、する必要がありますでしょうか?関数である場合、inheretanceは、オーバーライドの「セット」を分かりやすい方法でグループ化します。 1つの「登録」機能を持っていても、多くの部分を実装者に委譲することができます。これは、テンプレートパターンの古典的なケースです。

同じ機能のいくつかの異なる実装が必要ですか?ただ1つの場合、無関係は良いですが、多くの実装がある場合、代理人はオーバーヘッドを節約できます。

複数の実装がある場合は、プログラムを切り替える必要がありますか?あるいは、単一の実装のみを使用します。切り替えが必要な場合は、代理人の方が簡単かもしれませんが、特に#1の答えによっては注意が必要です。戦略パターンを参照してください。

保護されているメンバーにアクセスする必要がある場合は、それには関係ありません。それがパブリックにのみ依存することができれば、委任してください。

その他の選択肢としては、イベントと拡張メソッドもあります。

2

個人的には、私の手の中にいると、私はいつもデリゲートモデルに行きます。私は高次関数のシンプルさと優雅さが大好きです。しかし、モデルを実装する際には、メモリリークに注意してください。購読されたイベントは、.Netのメモリリークの最も一般的な理由の1つです。つまり、いくつかのイベントが公開されているオブジェクトがある場合、イベントは強い参照を作成するので、すべてのイベントが登録解除されるまで、元のオブジェクトは決して廃棄されません。

+1

あなたの答えをありがとう。 APIを作るときの問題は、残念ながらあなたがしたいことだが、他人がやりたいことです:p – GETah