6

プロジェクトでは、私たちのチームはオブジェクト リストを使用して、すべて同様の方法で処理する必要がある一連のデータに対して大量の操作を実行しています。特に、異なるオブジェクトが同じように動作するのが理想的です。これは、ポリモーフィズムによって非常に簡単に実現できます。私が抱えている問題は、継承が関係を持っているのではなく、関係であることを意味することです。たとえば、いくつかのオブジェクトにはダメージ カウンターがありますが、これをオブジェクト リストで使いやすくするために、ポリモーフィズムを使用できます。(人ダメージカウンターではありません。)

私が考えることができる唯一の解決策は、継承に頼るのではなく、クラスのメンバーが暗黙的にキャストされたときに適切なオブジェクト型を返すようにすることです。プログラミングの容易さと引き換えに、 is a / has a idea を忘れた方がよいでしょうか?

編集:より具体的には、私はC++を使用しているため、ポリモーフィズムを使用すると、派生クラスが単一のリスト内に存在し、ベースの仮想関数によって操作されるという意味で、異なるオブジェクトが「同じように動作する」ことができますクラス。インターフェイスの使用 (または継承を介してそれらを模倣すること) は、私が喜んで使用するソリューションのようです。

4

10 に答える 10

5

関係を強制できるようにインターフェイスを実装する必要があると思います C#でこれを行っています):

public interface IDamageable
{
    void AddDamage(int i);
    int DamageCount {get;}
}

これをオブジェクトに実装できます。

public class Person : IDamageable

public class House : IDamageable

そして、DamageCount プロパティには、人と家がある種の階層構造で互いに関連していることを暗示することなく、ダメージを追加できるメソッドがあることを確信できます。

于 2008-08-15T01:54:52.993 に答える
3

これは、多重継承を使用して実現できます。特定のケース (C++) では、純粋な仮想クラスをインターフェイスとして使用できます。これにより、スコープ/あいまいさの問題を発生させることなく、複数の継承を行うことができます。例:

class Damage {
    virtual void addDamage(int d) = 0;
    virtual int getDamage() = 0;
};

class Person : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d * 2;
    }

    int getDamage() {
        return damage;
    }
};

class Car : public virtual Damage {
    void addDamage(int d) {
        // ...
        damage += d;
    }

    int getDamage() {
        return damage;
    }
};

現在、Person と Car は両方とも「is-a」Damage です。つまり、Damage インターフェースを実装しています。純粋な仮想クラスの使用 (インターフェイスのようなもの) が重要であり、頻繁に使用する必要があります。将来の変更によってシステム全体が変更されることを防ぎます。詳細については、Open-Closed Principle を参照してください。

于 2008-08-15T03:41:05.930 に答える
1

Jon に同意しますが、別のダメージ カウンター クラスが必要な場合は、次のようにします。

class IDamageable {
  virtual DamageCounter* damage_counter() = 0;
};
class DamageCounter {
  ...
};

各 Damageable クラスは、独自の damage_counter() メンバー関数を提供する必要があります。これの欠点は、損傷可能なクラスごとに vtable が作成されることです。代わりに以下を使用できます。

class Damageable {
 public:
  DamageCounter damage_counter() { return damage_counter_; }
 private:
  DamageCounter damage_counter_;
};

しかし、複数の親がメンバー変数を持つ場合、多くの人は多重継承でクールではありません。

于 2008-09-16T09:56:36.310 に答える
0

現実的なもののために理想をあきらめる価値がある場合もあります。「正しく行う」ことで大きな問題が発生し、実際の利益が得られない場合は、間違った方法で行うことになります。そうは言っても、時間をかけて正しく行うことは価値があると思うことがよくあります。不必要な多重継承によって複雑さが増し、システムの保守性が低下する可能性があるからです。状況に応じて何が最適かを実際に判断する必要があります。

1 つのオプションは、これらのオブジェクトにDamageableから継承するのではなく、インターフェイスを実装させることDamageCounterです。このように、人ダメージカウンターを持っていますが、ダメージを受ける可能性があります。(インターフェイスは、名詞よりも形容詞の方がはるかに理にかなっていることがよくあります。) そうすれば、オブジェクトに一貫したダメージ インターフェイスをDamageable持たせ、ダメージ カウンターが基礎となる実装であることを公開しないことができます (必要な場合を除きます)。

テンプレート ルート (C++ などを想定) を使用する場合は、ミックスインを使用してこれを行うことができますが、下手に行うとすぐに醜くなる可能性があります。

于 2008-08-15T01:13:01.660 に答える
0

通常、「is a」と「has a」について話すときは、継承と合成について話しています。

うーん...ダメージカウンターは、派生クラスの1つの属性にすぎず、質問に関して「人はダメージカウンターです」という観点からは実際には議論されません。

これを参照してください:

http://www.artima.com/designtechniques/compoinh.html

途中で役立つかもしれません。

@ Derek : 言葉遣いから、基本クラスあると思いました。質問を読み直したところ、彼が何を言いたいのかわかりました。

于 2008-08-15T01:15:32.417 に答える
0

この質問は本当に紛らわしいです:/

太字の質問は非常に自由で、「依存する」という答えがありますが、あなたの例は、あなたが求めている文脈についてあまり情報を与えていません. これらの行は私を混乱させます。

すべて同様の方法で処理する必要があるデータのセット

どのように?セットは関数によって処理されますか? 別のクラス?データの仮想関数を介して?

特に、異なるオブジェクトが同じように動作するのが理想的です。これは、ポリモーフィズムによって非常に簡単に実現できます。

「同じように振る舞う」という理想とポリモーフィズムはまったく無関係です。ポリモーフィズムはどのように達成を容易にするのですか?

于 2008-08-15T01:17:13.803 に答える
0

@ケビン

通常、「is a」と「has a」について話すときは、継承と合成について話しています。

うーん...ダメージカウンターは、派生クラスの1つの属性にすぎず、質問に関して「人はダメージカウンターです」という観点からは実際には議論されません。

属性としてダメージ カウンターを持っているため、ダメージ カウンターを持つさまざまなオブジェクトをコレクションに入れることはできません。たとえば、人や車の両方にダメージ カウンターがある場合がありますが、ほとんどの言語では avector<Person|Car>や aなどを使用することはできません。vector<with::getDamage()>共通のオブジェクト基本クラスがある場合は、その方法でそれらを押し込むことができますが、getDamage()メソッドに一般的にアクセスすることはできません。

私がそれを読んだとき、それが彼の質問の本質でした。「特定のオブジェクトが同じではない場合でも、それらが同じであるかのように扱うために、is-a違反する必要がありますか?」has-a

于 2008-08-15T01:22:11.953 に答える
0

「正しく行う」ことは、最初から正しく行われていれば、システムを後で保守する人が理解しやすくなるという理由だけで、長期的にはメリットがあります。

言語によっては、多重継承のオプションがある場合もありますが、通常は単純なインターフェイスが最も理にかなっています。「シンプル」とは、過度になりすぎないインターフェースを作ることを意味します。単純なインターフェイスをたくさん用意し、モノリシックなインターフェイスをいくつか用意することをお勧めします。もちろん、常にトレードオフがあり、インターフェースが多すぎると、おそらく「忘れられた」ものになるでしょう...

于 2008-08-15T01:29:00.770 に答える
0

@アンドリュー

「同じように振る舞う」という理想とポリモーフィズムはまったく無関係です。ポリモーフィズムはどのように達成を容易にするのですか?

それらはすべて、たとえば、1 つの共通の機能を持っています。と呼びましょうaddDamage()。このようなことをしたい場合:

foreach (obj in mylist)
    obj.addDamage(1)

次に、動的言語が必要になるか、共通の親クラス (またはインターフェイス) から拡張する必要があります。例えば:

class Person : DamageCounter {}
class Car : DamageCounter {}

foreach (DamageCounter d in mylist)
    d.addDamage(1)

次に、特定の非常に有用な状況で同じPersonことを扱うことができます。Car

于 2008-08-15T01:29:19.193 に答える
0

ポリモーフィズムは継承を必要としません。ポリモーフィズムは、複数のオブジェクトが同じメッセージ シグネチャ (メソッド) を実装するときに得られるものです。

于 2010-01-18T21:29:48.753 に答える