作为一名C++程序员,我学到的一个重要且必不可少的规则是组合优先于继承(http://en.wikipedia.org/wiki/Composition_over_inheritance)。
我完全同意这条规则,该规则比起使用继承来使事情简单得多。
我有一个问题,应该使用“合成”来解决,但是我真的很努力。
假设您有一个供应商机器,并且您有两种类型的产品:
这两种类型的产品将需要在一个名为VendorCell的类中表示,该类包含单元格内容。
这两种产品具有相同的属性(dm),例如价格,数量等等。但是也包含一些不同的属性。
因此,在此处使用合成可能会导致以下结果:
class VendorCell {
private : // default access modifier
int price;
int quantity;
// int firstProductAttributeOnly
// char secondProductAttributeOnly
};
如您所见,注释行显示,对于一个单独的VendorCell,取决于包含的产品,这两个注释行中只有一个是有效的(另一条仅与另一种类型相关-例如,流体) 。
因此,我可能有一个VendorCell,里面有小吃,不需要它的secondProductAttributeOnly。
(对于VendorCell)组合是正确的解决方案吗?对你们来说似乎合适的是,有人将通过构造函数确定VendorCell类型,而一个DM(专用于另一种类型的DM)将根本不被使用(例如,将其标记为-1)?>
谢谢大家!
最佳答案
您偏爱组成而非继承的一般规则是正确的。这里的问题是您需要container of polymorphic objects,而不是可以容纳所有可能产品的巨型集合类。但是,由于有了slicing problem,您不能直接保存多态对象,但是需要通过(最好是智能的)指针来保存它们。您可以通过(智能)指针直接持有它们,例如
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
替换为包含VendorMachine
的单独类std::vector< VendorCell >
来重构此代码,以便获得更好的界面(例如具有货币兑换功能)