3

私がC++プログラマーとして学んだ重要で不可欠なルールの1つは、継承よりもコンポジションを優先することです(http://en.wikipedia.org/wiki/Composition_over_inheritance)。

私は、継承を使用した場合よりもはるかに単純になるこのルールに完全に同意します。

コンポジションを使用して解決する必要のある問題がありますが、それを行うのに本当に苦労しています。

ベンダーマシンがあり、次の2種類の製品があるとします。

  1. 個別の製品-スナックのように。
  2. 流動性のある製品-飲み物のように。

これらの2種類の製品は、セルの内容を含むVendorCellと呼ばれるクラスで表す必要があります。

これらの2つの製品は、価格、数量などのいくつかの同一の属性(dm)を共有していますが、いくつかの異なる属性も含まれています

したがって、ここでコンポジションを使用すると、次の結果が得られる可能性があります。

class VendorCell {
private : // default access modifier
    int price;
    int quantity;

    // int firstProductAttributeOnly
    // char secondProductAttributeOnly
};

コメント行は、含まれている製品に応じて単一のVendorCellの場合、これら2つのコメント行の1つだけが重要で使用可能であることを示しています(もう1つは他のタイプにのみ関連します-たとえば、流体)。

したがって、スナックが入ったVendorCellがあり、そのsecondProductAttributeOnlyは必要ありません。

(VendorCellの)構成は正しい解決策ですか?誰かがコンストラクターを介してVendorCellタイプを決定し、1つのDM(他のタイプ専用のDM)がまったく使用されない(たとえば-1としてマークする)ことはあなたたちにとって適切なようです?>

みなさん、ありがとうございました!

4

2 に答える 2

4

継承よりも構成を優先するというあなたの一般的なルールは正しいです。ここでの問題は、すべての可能な製品を保持できる巨大な集約クラスではなく、ポリモーフィックオブジェクトのコンテナが必要なことです。ただし、スライスの問題があるため、ポリモーフィックオブジェクトを直接保持することはできませんが、(できればスマートな)ポインタで保持する必要があります。次のような(スマート)ポインタで直接保持できます

class AbstractProduct { /* price, quauntity interface */ };
class AbstractSnack: public AbstractProduct { /* extended interface */ };
class AbstractDrink: public AbstractProduct { /* extended interface */ };
typedef std::unique_ptr<AbstractProduct> VendorCell;
typedef std::vector< VendorCell > VendorMachine;

AbstractSnack / AbstractDrinkから派生して、スナック/飲み物を定義するだけです。

class SnickersBar: public AbstractSnack { /* your implementation */ };
class CocaColaBottle: public AbstractDrink { /* your implementation */ };

次に、次のような製品を挿入または抽出できます。

// fill the machine
VendorMachine my_machine;
my_machine.emplace_back(new SnickersBar());
my_machine.emplace_back(new CocaColaBottle());

my_snack = my_machine[0]; // get a Snickers bar
my_drink = my_machine[1]; // get a Coca Cola bottle;

ポリモーフィックオブジェクトへのポインタを内部的に保持するラッパークラスを使用するBoost.Anyなどの他のソリューションもあります。を保持するtypedef別のクラスに置き換えることで、このコードをリファクタリングすることもできます。これにより、より優れたインターフェイスを取得できます(たとえば、両替機能を使用)。VendorMachinestd::vector< VendorCell >

于 2013-01-28T09:29:30.457 に答える
0

再利用するために継承します。

再利用するために作曲します。

異なる属性がある場合は、おそらく継承する必要があります。そうでない場合は、作成します。

いくつかのバリエーション:

class ProductVariety {
public:
    virtual void display(Screen& screen) = 0;
};

実装:

class Liquid : public ProductVariety {
public:
    virtual void display(Screen& screen) {
        //...
    }
}

構成バリエーション:

class Product
{
    int price;
    int quantity;

    unique_ptr<ProductVariety> variety;
}
于 2013-01-28T09:36:14.450 に答える