1

オブジェクトが特定のコンストラクターを使用してインスタンス化されたかどうかの確認について質問があります。検索エンジンの一部である SearchWithTwoLevelCore というクラスがあります。次のようなコンストラクタがあります。

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp)
    {
        //Initialize the two levels.
        S=s;
        lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0));
        lvl1 = SizeBoundedQueryCache(lvl2, 10);


    }

ここで、S、lvl1、および lvl2 はすべて、他のパブリック クラスのオブジェクトを保持するクラスで宣言されたプライベート フィールドです。次に、SearchWithTwoLevelClass 内にある実行したいパブリック メソッドがありますが、最初に、SearchWithTwoLevelCache を作成するために使用されたコンストラクターが上記のものであるかどうかを確認したいと思います。そうでない場合、メソッドは正しく実行されず、何らかの例外がスローされます。 t。これを行う最善の方法は何ですか?よろしくお願いします!

4

3 に答える 3

4

これは、リスコフの置換原理の重要性を示す良い例です。この回答で使用されている画像がとても気に入っています。

クラスに複数のコンストラクターがあり、メソッドの成功が呼び出されたコンストラクターに依存する場合、いくつかの選択肢があります。

ここでの主な問題は、オブジェクトの状態が呼び出されたコンストラクターに依存しているように見えることです。これは、実装の提示方法に関係なく、クラス全体で状態チェックが急増するため、最適な設計手法ではありません。

1) オブジェクトをより小さなオブジェクトにリファクタリングする

ここでの考え方は、コンストラクターはクラスの実行に必要なデータのみを要求する必要があるということです。それぞれが異なる量の引数とデータを必要とする複数のコンストラクターがある場合、このクラスは実際にはいくつかの異なるオブジェクトを表していると主張できます。

2) メソッドにデータ要件を適用します。

public SearchWithTwoLevelCache(ISearchCore s, ICurrentTimeProvider tp)
{
    //Initialize the two levels.
    S=s;
    lvl2 = TimeBoundedQueryCache(s.AsQueryDataSource, tp, TimeSpan(24,0,0));
    lvl1 = SizeBoundedQueryCache(lvl2, 10);
}

この状態は、実際にはクラス自体によって必要とされていないと主張することができます。実際に関数の前提条件である場合は、関数自体の要件にするためです。これにより、あいまいさがなくなります。

したがって、クラスは次のようになります。

public SearchWithTwoLevelCache(ISearchCore s)
{
  S = s;
} 

public Whatever PerformTwoLevelSearch(ICurrentTimeProvider tp) { }

例えば。

ここでの考え方は、クラス全体の状態に絶対に必要なデータのみをコンストラクターで提供することです。

もちろん、メソッド レベルでチェックを実装して例外をスローすることもできますが、クラスを使用している人にとっては、これは非常にイライラすることがあります。関数 1 を呼び出すには、コンストラクター 2 を呼び出して他の変数を設定する必要があることをどうやって知りましたか? 使用するインターフェイスをどのように知るのでしょうか? そのため、関数の条件にすることで、使用と保守の両方がはるかに簡単になります。

また、将来的にこのクラスを拡張することも難しくなります。メソッドの成功が他のいくつかのメソッドまたはコンストラクターを最初に呼び出すことに依存している場合、このロジックをリファクタリングして変更すると、すべてのクライアントも強制的に変更されます。

于 2013-06-24T08:52:50.877 に答える
1

クラス内でa を設定できpublic boolean property、特定のクラスでconstructorそれを作成できますtrue。このプロパティのデフォルト値は ですfalse

したがって、オブジェクトが obj1 の場合、関数を呼び出す前にこのブール値を確認できます。

if(obj1.public_property)
     // do function call

これは単なる解決策です。これよりも良い解決策があるかもしれません。

于 2013-06-24T08:47:44.623 に答える
0

迅速な解決策 (良くない) は、フラグを使用して、どのコンストラクターが呼び出されたかを示すことです。後でコード内のあらゆる場所で確認します。

必要なのは、実際には F# のDiscriminated Unionsです。ただし、C# には then がないため、クラスを抽象化して、interfaceそのインターフェイスに別の具体的な実装を提供する必要があります。

これで、メソッドのオーバーロードを (具体的な実装ごとに) 使用して、どの具体的な実装を使用するかを決定できるようになりました。

于 2013-06-24T08:53:41.140 に答える