6

背景:私はまだ C# の初心者であり、これは継承を使用した最初の大きなプロジェクトです。次の話は、私の現在の状況を単純化した例です。

というクラスがあるとしLivingOrganismます。すべての生物は、このクラスをベースとして使用し、すべての生物に共通する機能を継承できます。

derivedこれらのクラスのいくつかに取り組んでいたときに、バナナと人間が非常に似ていることがわかりました。あまり意味がなく、見た目も似ていませんが、「機能」のほとんどは共通しているようです。

コードの重複はよくないので、メンテナンス コストを削減するために新しいクラスを作成しました。このクラスの名前: BananaHuman. 私HumanのクラスとBananaクラスはから継承しBananaHumanます。


問題:

BananaHuman に問題はありません (つまり、BananaHuman の意味と存在理由を理解しています)。しかし、最終的には、他の人 (継承を (完全に) 理解していない人でも) は、私のLivingCreatures.dllを使用する必要があります。また、「B」と入力したときにインテリセンスが BananaHuman を提案する理由も理解できません。

そして、次のコードを検討してください。

//Valid and makes sense.
foreach(LivingOrganism foo in cityOfNeyYork) { /*embedded statement*/ }

Living Organismしかし、 で置き換えると、それがどれほど奇妙/混乱するか想像してみてくださいBananaHuman

または(名前空間BananaHuman privateで定義された要素をそのように明示的に宣言することはできません) を作成できません。私もそうしなければならないので、それを作ることはできません。これを試してみると、問題があるというエラー メッセージが表示されます。protectedprotected internalinternalHumanBanana publicinconsistent accessibility

明らかなことを見逃しているように感じますが、どうすればよいですか? いくつかのオプション/質問が残っています。

  1. BananaHuman混乱を避けるために「非表示」にすることはできますか?
  2. BananaHumanのように非常に長く技術的なものに書き直す必要がDnaRelatedOrganismsType[X]ありますか? ここで、「X」はそれらの固有の関係を表します。
  3. 何かを変更する必要がある場合は、単に削除BananaHumanし、継承しHumanて継承し、追加のメンテナンスを行う必要がありますか?BananaLivingOrganism
  4. 私が完全に見逃している別の解決策はありますか?

私は周りを検索しましたが、この状況の「固定パターン」を見つけることができませんでした. 似たようなタイトルのこの質問を見つけましたが、まったく別のことを尋ねているように見えるため、回答が当てはまるかどうかはわかりません。

どんな助けでも大歓迎です!

4

2 に答える 2

5

を使用EditorBrowsableAttributeしてクラスに適用できます。これにより、人々があなたの .dll を使用している場合、クラスが Intellisense から消えます。dll の代わりにプロジェクトを参照している場合、それは引き続き表示されます。

次のように使用します。

[EditorBrowsable(EditorBrowsableState.Never)]
public class BananaHuman
{
    //....
}

したがって、.dll を提供していただければBananaHuman、Intellisense でポップアップが表示されません。しかし、Banana または Human クラスを調べると、それが継承されていることがわかりますBananaHuman。このEditorBrowsable属性は、Intellisense からそれを消すだけです。何が必要なのですか。

于 2013-08-21T08:36:38.177 に答える
0

BananaHuman既存の答えは、インテリセンスから隠すという特定の問題に対する優れた技術的解決策です。BananaHumanしかし、OPはデザインの変更についても尋ねているので、の存在がコードの匂いであり、おそらくリファクタリングの候補になる理由について簡単に回答することも質問の範囲内であると思います.


5 つの重要な設計原則を表す SOLIDの頭字語を聞いたことがあるかもしれません。単一責任の原則(SRP) とオープン/クローズドの原則(OCP)BananaHumanの 2 つに反します。

バナナと人間は多くの DNA を共有している可能性がありますが、コードと同様に進化することも予想され、おそらく互いに別々に進化します。同じ DNA が常に正確に共有されているとは限りません。SRP は、クラスが 1 つの責任のみを持つべきである、または (同等に) 変更する理由が 1 つだけであるべきであると述べています。しかし、BananaHumanには常に、少なくとも 2 つの考えられる変更理由 ( の仕様Bananaの変更またはの仕様の変更) が自動的に存在しHumanます。

BananaHumanすべての一般的な基本クラスではなく、なぜこれが特に当てはまるのですか? 基本クラスは、他のクラスと同様に、1 つの明確に定義された概念を表す必要があるためです。したがって、たとえばMammal、哺乳類の概念を構成する機能が変更された場合にのみ変更する必要があります。特定の哺乳類が毛を失うように進化した場合、変化するのは基本クラスではなく、その動物のクラスMammalです。BananaHuman一方、 は定義上、「バナナと人間の両方に共通する機能」であるため、常に少なくとも2 つに結合されます。1つの概念ではなく。同様に、バナナと人間の間には他にあまり関係のない共通点がいくつかあるかもしれません。これらすべてを 1 つのクラスに押し込むと、まとまりが減り、より多くの責任が 1 つの場所に積み上げられます。

OCP では、ソフトウェア エンティティ (インターフェイス、クラス、メソッドなど) は拡張に対してオープンである必要がありますが、要件が追加または変更された場合の変更に対してクローズされている必要があります。Bananaたとえば、および と同じ特性を共有する別の生物を追加した場合Human、名前を変更する必要があります。または、一部の特性のみを共有する場合は、基本クラスをシャッフルする必要があり、これが複数回発生した場合、複数の継承の問題が発生する可能性さえあります. OCP違反につながる状況は他にもたくさんあると思います。


それで、あなたは何をすべきですか?

上記を読んで、 の特徴付けBananaHumanが不公平で、実際には非常に明確に定義された概念にマッピングされていると思われる場合は、実際のMammal名前に変更してください! 必要な操作はこれだけです。おそらく準備完了です。名前が長いかどうかは問題ではありません (ただし、理想的には簡潔な方がよいため、長さが複数の単語を 1 つの一連の単語に詰め込んでいることを示していないことを確認する必要があります)。

それが答えでない場合は、継承よりも構成のアイデアを検討してください。たとえば、すべてが肺を持つ複数の生物がある場合、LivingOrganismWithLungsクラスを作成する代わりにクラスを作成しLungs、肺を持つすべての生物にインスタンスを含めます。このように、共通の機能を独自のクラスに分離できれば、より優れたソリューションが得られます。

これらの両方が実際に不可能な場合 (まれですが、発生する可能性があります)、BananaHuman残されている最良のオプションである可能性があります。SRP および OCP の問題と Don't Repeat Yourself (DRY) 違反を評価するのは、あなたの判断次第です。

于 2014-06-12T23:35:41.653 に答える