【问题标题】:Liskov Substitution Principle with multiple inheritance heirachies具有多重继承层次结构的 Liskov 替换原则
【发布时间】:2015-10-21 20:24:25
【问题描述】:

我正在尝试提出一个面向对象的设计,但很难满足 Liskov 替换原则。这是一个说明性示例:

class Food
{
    public:
    virtual void printName() {
    //......
    }
};
class Fruit : public Food
{
};
class Meat : public Food
{
};
class Animal
{
    public:
    Food *_preferredFood;
    virtual void setFoodPreference(Food *food)=0;

};
class Carnivore: public Animal
{
    public:
    void setFoodPreference(Food *food) {
        this->_preferredFood = dynamic_cast<Meat *>(food);
    }
};
class Herbivore: public Animal
{
    public:
    void setFoodPreference(Food *food) {
        this->_preferredFood = dynamic_cast<Fruit *>(food);
    }
};

如何执行以下操作:

  1. Animal 的每个子类都应允许设置食物偏好,而不会破坏 LSP
  2. 每个派生类动物的食物偏好是食物的一个子类

例如,如果有人扩展 Animal 以创建 MarineMammal,则食物偏好可能是 Fish(他们将通过扩展 Food 创建)。

【问题讨论】:

  • 出于兴趣,您正在寻找的实际多态行为是什么?即客户端代码将针对基类调用哪些确切的方法?我问这个是因为我认为你冒着解决错误问题的风险。动物可能乍一看像一个遗传问题,但实际上它更可能是一个特征问题。
  • 你说得对,我不是在寻找多态行为。我真正想要的是任何扩展Animal 来定义正确的setFoodPreference 函数的人。当然我可以争辩说我想打电话给setFoodPreference。

标签: c++ oop virtual-functions


【解决方案1】:

当Carnivore::setFoodPreference 只接受Meat 和Herbivore::setFoodPreference 只接受Fruit 时,则它们不遵守同一合同。这意味着它们实际上不是相同的方法。当你调用这个方法时,你必须知道你是在处理肉食动物还是草食动物,以避免传递错误的类型。当您忘记检查这一点时,您可能会创建一个错误,该错误会在运行时以强制转换错误的形式表现出来。

解决办法是把这两种方法分开。

我建议您从公共接口中删除 setFoodPreference,而是将方法 Carnivore::setMeatPreference(Meat *meat) 和 Herbivore::setFruitPreference(Fruit *fruit) 直接添加到子类中。这样,任何设置食物偏好的代码都必须知道它正在处理哪种动物和哪种食物,因此您不能再编写试图设置不兼容食物类型的代码。

在内部,这两种方法都可以从公共基类中设置protected Food *_preferredFood。或者更好的是,调用protected void setPreferredFood(Food *food),它是private Food* _preferredFood 的设置器。该变量绝对不应该公开以确保正确封装。

【讨论】:

  • 我想我应该保持 _preferredFood 私有,并使 setFoodPreference protected virtual 。因为我需要强制派生类允许设置首选项。
  • @user2308211 为什么是virtual?当任何子类仅通过自己的方法调用该方法时,您可以将任何特定于子类的代码放在那里。
  • 我应该说,纯粹是虚拟的。确保他们实现这些方法。虽然它不是一个完整的解决方案,但有人可以从 Animal 派生,并且只实现 setFoodPreference。
  • 标记为未答复,以邀请进一步的答复。
猜你喜欢
  • 2014-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
相关资源
最近更新 更多