web-dev-qa-db-ja.com

メンバーの異なるサブセットを持つクラスの共通インターフェースを作成する方法

どうやって入れたらいいのか分からないけど、できるだけわかりやすくしよう

多くのクラスを作成しているプロジェクトがあり、それらのクラスにはいくつかの共通のプロパティとメソッドがありますが、それらのメソッドには異なるコードが含まれている可能性があります。

したがって、すべてのクラスで継承できるようにインターフェイスを作成することにしました。すべてのクラスにはinsert, update, deleteのような同じメソッドがあり、それらのメソッド内に異なるコードが含まれますが、すべてのクラスにいくつかのような同じ構造は、挿入メソッドを持っていますが、更新はありません。インターフェイスを継承する場合、そのインターフェイスのすべてのメンバーに対して、必要のないパブリック宣言を提供する必要があります。

トリック2抽象クラスについても考えましたが、抽象クラスも1つ作成しましたが、同じ問題で、すべての抽象メンバーをパブリックで実装する必要があります。

とても長い話です

クラスのインスタンス化できないブループリントとして機能し、多くのクラスに継承できる共通の継承可能な構造を作成したいのですが、多くのクラスでは、そのすべてのメンバーを実装したくありません構造

注:一部の人が示唆したように、私はno-op(何もしない、またはnullを返す空のメソッドなど)を実行できますが、それらの不要なメンバーがインテリジェンス中に表示されるため、私が探している解決策ではありません。私が避けたいこと。

どうやってやるの ?

7
yogi

これを行う1つの方法は、3つのメソッドと1つのインターフェイスを用意し、それをいくつかの抽象クラスで実装することです(これらは完全な実装の基本クラスになります)。

これらの抽象クラスは、必要ない必要なメソッドのみを実装し、no-ops(何もしないか、nullなど)。

実際の実装クラスは、これらの抽象クラスを継承し、必要な操作のサブセットのみを実装します。


別のオプションは [〜#〜] isp [〜#〜] (インターフェース分離の原則)を遵守し、必要な各動作に1つずつ、いくつかのインターフェースを用意することです。

更新:

この2番目のオプションは、IntelliSenseに特定のメソッドが表示されないようにするという要件に適しています。ただし、これは、単一の継承ツリーを使用することはできないが、それを分離することを意味します(モデルの説明から、これはおそらく正しい解決策です)。

7
Oded

単純な答えは、複数のインターフェイスを作成することです:InsertableUpdateableDeleteableなど。ただし、クラスに同様のメソッドがあるからといって、 必要継承構造を共有します。 callsというコードを再利用する必要がある場合にのみ、継承を使用します。たとえば、さまざまなタイプのさまざまなオブジェクトの束を保持するコンテナが必要で、insert()そのコンテナ内のすべてのもの。

11
Karl Bielefeldt

あなたが話しているのは polymorphism で、これは文字通り多くの形を持っていることを意味します

たとえば、Eat(Food food);というメソッドを持つAnimalという基本クラスがあるとします。次に、AnimalDogCatのように、Henから継承する3つのクラスがあるとします。

これらのすべてのサブクラスにはEatメソッドが必要ですが(基本クラスのメンバーをオーバーライドすることにより)、それぞれに独自の実装(異なる方法で実行)を含めることができます。

これは、inheritanceを使用して、スーパークラス(基本クラス)から継承するか、1つまたは多くのインターフェース(@Odedによると、 1つの大きなインターフェースではなくインターフェース)。

私の頭に浮かぶもう1つのオプションは、C#でmixinを実装することですが、私はそれが得意ではありません。ただの手がかり;).

0
Saeed Neamati

問題は、クラスを使用するプログラムが知らないため(そして知りたくないため)、どっち。何もしない方法はこの問題の良い解決策になる可能性がありますが、それらは理にかなっていなければなりません。呼び出し側プログラムが呼び出しを行う場合、何もしない場合でも不便ではありません。

次のステップは、機能を返すメソッドを用意することです。そのため、特定のオブジェクトが処理できないメソッドを呼び出さないでください。 CanFlyがfalseを返す場合、呼び出し元はFlyToLAを呼び出さないことを知っています。もちろん、これは呼び出してはならない何もしないメソッドをたくさん残します-せいぜい厄介な状況です。

solutionは、すべてのクラス/インターフェイスにGetFlightインスタンスを返すFlightメソッドを持たせることだと思います( "Flight"はクラスorinterface--interfaceが最適に機能する可能性があります)。そのメソッドがnullを返す場合、オブジェクトは飛行しません。 Flightオブジェクトを返す場合、thatオブジェクトにはフライトに関連するすべてのメソッドが含まれているため、それらは存在し、適用可能で存在しない場合に利用できますそうでない場合は使用できません。

また、GetDriveGetAccountingGetPersonellなどの他のメソッドを使用することもできます。Accounting会計のサブセット用に、さらに多くの「取得」メソッドを持つインターフェース。このテーマには多くのバリエーションがあります。

0
RalphChapin

.netでは、インターフェースが他のインターフェースを継承する場合、構成インターフェースを実装するクラスを、それを宣言するだけで、追加のコーディングを必要とせずに、結合インターフェースの実装と見なすことができます。したがって、IThisIThat、およびIThisOrThatインターフェースを1つ持つよりも、「すべてを行う」インターフェースを1つ持つよりも便利です。インターフェースは、処理できないインターフェースメソッドのスタブを実装する必要はありません。さらに、オブジェクトをコンパイル時に両方のインターフェイスを処理する必要があるコードは、IThisOrThat型のパラメーターを受け入れることにより、そのようなオブジェクトを要求できます。

ただし、このアプローチにはいくつかの制限があります。

  1. タイプキャストなしでタイプセーフなコードを可能にすることができますが、コレクションが複数のインターフェイスを実装するオブジェクト(たとえば、{IThis、IThat})を保持することを指定するリモートで良い方法はありません。必要なすべてのインターフェースを含む複合インターフェース。ジェネリックスはパラメーターとローカル変数で多くのことを助けることができますが、混合型のコレクションではあまり役に立ちません。
  2. コードは、それ自体のためだけでなく、他のコードにオブジェクトを与える目的のためにもオブジェクトを保持できます。コードは、 `IThis`の実装に必要なオブジェクトと、渡されたオブジェクトを受け入れることが期待されるデリゲートを受け入れる場合があります。渡されたオブジェクトのパラメータータイプが `IThis`である場合、渡されたインスタンスが実際に後者のインターフェースを実装していても、コードはそれを` IThisOrThat`を期待するデリゲートに渡すことができません。ジェネリックの使用はここで役立ちますが、常に完全にスムーズになるとは限りません。
  3. コードには、正確な機能が異なるインスタンスがある場合があります。場合によっては、インスタンスに、より機能的なインスタンスを生成するメソッドが含まれることがあります。たとえば、不変クラスには、不変クラスのデータで初期化された可変クラスインスタンスを返す `AsMutable`関数がある場合があります。ゲッターを含むタイプ「IReadableFoo」のフィールドを持つよりも、ミュータブルクラスと不変クラスの両方によって実装され、「getter」と「setter」の両方のメソッドを含むタイプ「IMaybeMutableFoo」のフィールドを持つ方が便利かもしれません。ただし、セッターはなく、フィールドが変更可能なオブジェクトを保持していることをテストした後でも、フィールドに書き込みたい場合は常に型キャストが必要です。

私は複合インターフェースのアプローチが好きですが、セミ複合インターフェース(他のインターフェースを実装しますが、そのように有用であるとは保証されていません)を使用することも役立ちます。

0
supercat