在C++中使用多态和继承来处理一篮子水果的正确方法是什么?

Cor*_*ein 2 c++ polymorphism inheritance

假设我正在编写一个处理一篮子水果的机器人.橙子需要榨汁,苹果需要切片,香蕉需要去皮.幸运的是,我们的机器人拥有榨汁,切片和去皮所需的精确工具.

Robot::processFruit(List<Fruit*> basket)
{
  foreach(Fruit *fruit, basket)
  {
    if( ? ) { juiceIt(fruit); }
    else if( ? ) { sliceIt(fruit); }
    else if( ? ) { peelIt(fruit); }
  }
}
Run Code Online (Sandbox Code Playgroud)

这是我偶尔遇到的问题的一般示例.我有一种直觉,我的设计中出现了一些问题,因此我甚至导致了一个processFruit()函数,因为我使用的是面向对象的语言,但它似乎没有一个干净的解决方案来解决这个问题.

我可以创建一个enum FruitType { Orange, Apple, Banana}然后需要每个水果来实现virtual FruitType fruitType(),但那时似乎我只是重新实现一个类型系统.

或者我可以有功能virtual bool isOrange(); virtual bool isApple(); ...但是我们可以看到它会很快失控.

我也可以使用C++ typeid,但这个wikibook

RTTI只应在C++程序中谨慎使用.

所以我不愿采取这种方法.

在设计面向对象程序时,似乎必须缺少一些基本和关键的东西.C++是关于继承和多态的,所以有更好的方法来解决这个问题吗?

更新:我喜欢拥有一个通用process()功能的想法,所有功能Fruit都需要实现.但是,如果我现在想要添加一个Lemon并且想要榨汁呢?我不想复制榨汁代码,所以我应该创建一个class Juicable : public Fruit橘子和柠檬Juicable吗?

mea*_*gar 6

告诉,不要问:

程序代码获取信息然后做出决策.面向对象的代码告诉对象做事.
- 亚历克夏普

您想要定义一个Fruit具有虚process方法的基类.苹果,橙子和香蕉各自实施自己的版本,process为这种类型的水果做正确的事情.您的机器人需要做的就是将下一个机器Fruit*拉出篮子,然后打电话process给它:

Robot::processFruit(List<Fruit*> basket)
{
  foreach(Fruit *fruit, basket)
    fruit->process();
}
Run Code Online (Sandbox Code Playgroud)

你在代码示例中执行的if/else/else处理的类型正是多态意味着要避免的那种,并且它绝对不是以"OOP"方式执行此操作.

  • 水果不应该在逻辑上意识到如何处理它,机器人应该测试水果,看看它怎么做.. (3认同)
  • @DoryZidon不,绝对没有.这完全是错误的.你将为世界上每种类型的水果定义一个不断增长的if/else/else/else/else,这不是**OOP.具有数百个分支的if/else是编写此代码的完全错误的方法.那时,你应该使用结构. (3认同)
  • @DoryZidon现在你只是为了避免某种"怪异"的东西而在抽象层中蠢蠢欲动,在一个已经非常*设计的例子中.我无法认真投入关于水果篮架构的辩论.我要说的是,我认为严格遵守这样一种观念,即你的对象*必须*反映物理世界中的工作方式对OOP造成巨大损害,并且可以产生严重过于复杂的架构而没有真正的好处. (3认同)
  • @BenjaminLindley我不同意.将这种逻辑封装在水果中是迄今为止最容易和最干净的实现方式,并且在实际遵守OOP租户方面是最纯粹的.我真的不在乎"现实生活"中的水果不知道如何处理自己.正如我所说,这是一个非常人为的例子,我真的不能被要求进一步争论. (3认同)
  • 我们使用OOP来增强可重用性和可扩展性,但不能完全复制世界.以特定方式设计类应该具有软件工程优势. (3认同)
  • @meagar:Dory所说的绝对不是错误的,并且绝对是正确的OOP.各种物体可以为水果做无限的事情.*"为了让我为人类消费做准备,机器人应该做些什么"*绝对不应该*成为水果的功能.这在逻辑上是机器人的工作来确定的. (2认同)