共通フィールドを基本クラスに移動するタイミングは?


16

現在、2つの派生クラスがAあり、B、両方に共通のフィールドがあり、基本クラスに入れるかどうかを判断しようとしています。

基本クラスから参照されることはありません。また、道路のある時点で別のクラスが派生した場合C、を持たない場合、_field1「最低特権」(または何か)のプリンシパルは違反されませんだった?

public abstract class Base
{
    // Should _field1 be brought up to Base?
    //protected int Field1 { get; set; }
}

public class A : Base
{
    private int _field1;
}

public class B : Base
{
    private int _field1;
}

public class C : Base
{
    // Doesn't have/reference _field1
}

18
私はあなたが私たちに何の任意のアイデアを与えていないので、この質問は不明だと思うBaseABC、と_field1しています。それらは重要な詳細であり、省略すべきではありません。質問を編集して、それらが何であるかについて話す必要があると思います。
タナースウェット

回答に基づいて、Vehicleを再構築して仮想サスペンションを作成します。次に、CarとBicycleにWheelsとBoatにBuoyancyを追加すると、抽象度が上がります。私の抽象化が特定の設定に直接つながる場合、チェーンの概念を十分に移動していないことがわかります。
パトリックヒューズ

6
コードの重複を避けるために、クラスの継承を使用しないでください。振る舞いの継承と拡張、つまり多態性に使用します。共通フィールドを基本クラスに移動するのはそれが論理的に同じフィールドであり、それぞれのコンテキストで偶然同じ名前を共有する2つの無関係な情報ではない場合のみです
ブランドン

なぜ最初から基本クラスがあるのですか?
jpmc26

回答:


34

それはすべて、あなたが解決しようとしている正確な問題に依存します。

具体的な例を考えてみましょう。抽象基本クラスがVehicleあり、現在、具体的な実装BicycleとがありCarます。あなたは移動を考えているnumberOfWheelsからBicycleCar車両に。これをする必要がありますか?番号!すべての車両に車輪があるわけではないからです。Boatクラスを追加しようとすると、クラスが壊れるということを既に伝えることができます。

さて、もしあなたの抽象基底クラスがそうだったなら、そこにメンバー変数WheeledVehicleを持つことは論理的numberOfWheelsです。

ご覧のとおり、単純なyesまたはnoの答えではないため、同じロジックを問題に適用する必要があります。


3
0が有効なnumberOfWheelsであることを一時的に受け入れることができます。ただし、最終的にroll()メソッドを追加する可能性があり、その時点でサブクラスのアイデアは先見の明になります。
user949300

11
ボートには車輪がありません。それは何を壊しますか?
D Drmmr

14
@DDrmmrボートのホイールが0であるということではなく、ホイールがボートの概念として存在しないこともあります。したがって、モデルはそれを許可すべきではありません。
ピーターM

10
私のポイントは、例が悪いということです。車両に車輪が付いていないことを示す概念上、ボート(たまたまボート)に概念的な問題はありません。
D Drmmr

10
その後、パドルボートを保管する必要があるとき、それはすべて地獄に行きます。
IllusiveBrian

13

論理的に言えば、サブクラスで複製されたフィールドと基本クラスで共通のフィールドを配置する以外に、3つのオプションがあります。2つの間で共通のプロパティを持つ階層に新しいサブクラスを導入することです。@Peteは完全にそこに行くことなくこれをほのめかします。

@Peteの例を使用して、元の基本クラスから派生するWheeled Vehicleの(場合によっては抽象的な)サブクラスを導入しますが、2つのサブクラスはそこから派生します。したがって、元の基本クラスはホイールで汚染されていませんが、ホイールの共通性はDRYです(ホイールを持つサブクラス間で繰り返されません)。

もちろん、これはあなたの目的にとってはやり過ぎかもしれませんが、クラス階層メカニズムによってサポートされています。


これは、実際に私が決定したことです(AとBはほとんど重複しているため、BはAから派生します)。
サミス

9

ここで悪魔の擁護者を演じます。

今は何もないでください

乾燥していますか?いいえ。しかし、後で簡単に元に戻せない時期尚早な抽象化よりも、少し重複させる方が良いでしょう。プロパティを共通の基本クラスに移動するリファクタリングは簡単です。反対に行くことはありません。成り行きを見守る。

この種の決定をするとき、私は「3の規則」を使用する傾向があります。たとえば、3つの異なる場所で同じことを繰り返した後、それだけでチェーンを上に移動することを検討します。注意:あなたは2歳です。


2
賢明な観察は、私が言うには、決定を下すために必要です。
レーダーボブ

1
私はほとんど同意しますが、「今すぐ」(私たちが見ているような余分なコードはありません)両方向のリファクタリングは簡単です。しかし、フィールドを使用する追加のコードがある場合、両方向のリファクタリングはかなり難しくなる可能性があります。
Doc Brown

2

一般的に、基本クラスに移動します。ここには「はい/いいえ」の目標はないと思います。なぜなら、ここにはトレードオフがあるからです。未使用のフィールドを運ぶことと複雑さを減らすことです。

私は通常、共有される可能性のあるものをすべて含む「重い」基本クラスを好みます。すべての派生クラスで子孫のシリアル化メソッドが必要ないため、これによりファイルへのシリアル化が簡単になります。ただし、そのような問題や同様の問題がない場合、またはメモリ使用量を削減するためにできる限りのことをする必要がある場合は、必要なフィールドのみを保持することで問題ありません。

フィールドの数が非常に限られている場合、共通フィールドを導入する「中間」クラスは問題ありません。ただし、さまざまな組み合わせで多数のフィールドを使用すると、アプローチによって複雑さが大幅に増加し、それぞれが特定のフィールドセットを導入する多くの中間クラスにつながることに注意してください。これはメンテナンスの問題になる可能性があります。


私の例はささいなことですが、それはまだ生産コードです。あなたは、階層を「重い」基本クラスで「妥協」することについて良い議論をします。私もそのような場合に傾いていると思います。
サミス

1
@samis:「A、B、C」および「Base」という名前のクラスを、1つのフィールドだけで使用し、プロダクションコードではメソッドを使用しませんか?私はそれを疑います。
Doc Brown
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.