12

これはちょっとおかしな質問です。それぞれに関連付けられた特定の機能を持つ一連のオブジェクト (設計時に既知) を作成したいと考えています。「デリゲート」を含むことができるオブジェクトのプロパティを指定することで、これを行うことができます。

public class StateTransition {
    Func<bool> Condition { get; set; }
    Action ActionToTake { get; set; }
    Func<bool> VerifyActionWorked { get; set; }
}

StateTransition foo = new StateTransition {
    Condition = () => {//...}
    // etc
};

または、抽象クラスを使用して、作成するオブジェクトごとにこれを実装することもできます。

public abstract class StateTransition {
    public abstract bool Condition();
    public abstract void ActionToTake();
    public abstract bool VerifyActionWorked();
}

class Foo : StateTransition {
    public override bool Condition() {//...}
    // etc
}

Foo f = new Foo();

これら 2 つの方法の実際の結果 (設計時と実行時の作成) はまったく異なることを認識しています。

アプリケーションに適した方法を選択するにはどうすればよいですか?

4

7 に答える 7

5

最初のアプローチは、生のデリゲートよりもイベントに適しているように見えますが、どうでもいいです。

それらの間の重要な要因は、何が起こるかを誰が制御するかということです。

呼び出し元が合法的に何でもできる場合は、イベント アプローチで問題ありません。Buttonシステムは、クリックしたときに何が起こるかを追加するためだけにa をサブクラス化することを強制しません(ただし、そのようにすることはできます)。

「起こり得ること」がかなり制御されていて、呼び出し元ごとに異なることをしたくない場合は、サブクラスのアプローチが適しています。これにより、「やるべきこと」が実際には非常に少数のオプションである場合に、すべての発信者が何をすべきかを伝える必要がなくなります。ベースタイプのアプローチでは、サブクラスを制御する機能提供されます。たとえばinternal、ベースクラスにコンストラクターのみを持たせることで (同じアセンブリ内の型、または を介し​​て指定されたアセンブリ内の型のみ[InternalsVisibleTo(...)]がサブクラス化できるようにします)。

次の方法で 2 つ (オーバーライドとイベント) を組み合わせることもできます。

public class StateTransition {
    public event Func<bool> Condition;
    protected virtual bool OnCondition() {
        var handler = Condition;
        return handler == null ? false : handler();
    }
    public event Action ActionToTake;
    protected virtual void OnActionToTake() {
        var handler = ActionToTake;
        if(handler != null) handler();
    }
    public event Func<bool> VerifyActionWorked;
    protected virtual bool OnVerifyActionWorked() {
        var handler = VerifyActionWorked;
        return handler == null ? true : handler();
    }
    // TODO: think about default return values
}

デリゲート/イベント アプローチで考慮すべきもう 1 つのことは、次のとおりですnull3 つすべてが必要な場合は、コンストラクターで 3 つすべてを要求することをお勧めします。

于 2013-01-10T08:05:57.670 に答える
2

デリゲート ソリューションは、次の場合に役立ちます。

  • オブジェクトを動的に作成したい、つまり、いくつかの条件に応じて各メソッドの実装を選択したい。
  • オブジェクトの存続期間中に実装を変更したい。

それ以外の場合は、オブジェクト指向のアプローチをお勧めします。

于 2013-01-10T08:10:02.267 に答える
0

オブジェクトが設計時に既知であると言っている場合、オブジェクトの動作を動的に(実行時に)変更する必要はないように思われます。したがって、「委任」アプローチを使用する理由はないと思います。

于 2013-01-10T08:06:38.093 に答える
0
  • 解決策 1 にはより多くの可動部分があるため、懸念事項をより細かく分離できます。1 つのオブジェクトConditionで特定のStateTransitionがどうあるべきかを決定し、別のオブジェクトで を定義することができますActionToTake。または、1 つのオブジェクトですべてを決定することもできますが、異なる基準に基づいています。ほとんどの場合、IMO で最も有用なアプローチではありません。特に、複雑なコストがわずかに追加されることを考慮してください。

  • ソリューション 2 では、各StateTransition導関数はまとまりのある全体であり、条件をチェックする方法は、アクションを実行または検証する方法から切り離すことはできません。

両方のソリューションを使用して、制御の反転を実現できます。つまり、両方のソリューションを使用すると、StateTransition直接の消費者がStateTransition使用するフレーバーを制御せず、代わりに決定を外部オブジェクトに委譲することができます。

于 2013-01-10T11:00:08.097 に答える
0

これが堅実な答えというよりも意見である場合...

デリゲートまたは抽象/仮想メソッドが1つしかない場合、2つは多かれ少なかれ同等になると思います。結局のところ、デリゲートは、1 つのメソッドだけのインターフェイスを実装することを避けるための便利なショートカットと考えることができます。

3 つのメソッドがあるこの場合、基本クラスのアプローチが最も実用的です。

2 つのことを完全に同等にするために、空の仮想メソッドを持つ基本の非抽象クラスを使用できます。これにより、派生クラスがそれをオーバーライドしない場合、null デリゲート プロパティを持つのと同じになります。

于 2013-01-10T08:02:55.527 に答える