具有多重继承继承关系的 Liskov 替换原则 [英] Liskov Substitution Principle with multiple inheritance heirachies

查看:40
本文介绍了具有多重继承继承关系的 Liskov 替换原则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to come up with an object oriented design, and having difficulty satisfying the Liskov Substitution Principle. Here is an illustrative example:

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(他们将通过扩展食物).

Fore example, if somebody extends Animal to create MarineMammal, the food preference might be Fish (which they will create by extending Food).

推荐答案

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

When Carnivore::setFoodPreference only accepts Meat and Herbivore::setFoodPreference only accepts Fruit, then they do not comply to the same contract. That means they are not actually the same method. When you call this method, you have to know if you are dealing with a carnivore or a herbivore to avoid passing the wrong type. When you forget to check this, you risk creating a bug which manifests in form of a casting error at runtime.

解决方案是将这两种方法分开.

The solution is to separate these two methods.

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

I would recommend you to remove setFoodPreference from the public interface and instead add methods Carnivore::setMeatPreference(Meat *meat) and Herbivore::setFruitPreference(Fruit *fruit) directly to the subclasses. That way any code which sets the food preference must know what kind of Animal and what kind of Food it is dealing with, so you can no longer write code which tries to set an incompatible food type.

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

Internally, both methods may set a protected Food *_preferredFood from the common base class. Or even better, call a protected void setPreferredFood(Food *food) which is a setter for a private Food* _preferredFood. That variable should definitely not be public to ensure proper encapsulation.

这篇关于具有多重继承继承关系的 Liskov 替换原则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆