gpt4 book ai didi

java - Liskov 替换原则和多重层次结构

转载 作者:行者123 更新时间:2023-11-30 02:32:30 24 4
gpt4 key购买 nike

此问题是 this 的后续问题.我正在尝试定义涉及多个基派生对的类层次结构。作为说明性示例,假设我有一个类 Animal 和一个类 FoodAnimal 有一个纯虚函数来标记它的食物偏好,以食物为参数。

class Food
{
public:
virtual void printName() {
//......
}
};

class Animal
{
public:
Food *_preferredFood;
virtual void setFoodPreference(Food *food)=0;

};

我需要编写只处理这些基类的代码,并调用纯虚函数。例如,我有一个 ZooManager 类,它为每只动物设置食物偏好。

class ZooManager
{
vector<Aninal*> animals;
public:
void setAllPreferences(vector<Food *> foods) {
assert(animals.size() == foods.size());
for(int i =0;i<animals.size();i++) {
animals[i]->setFoodPreference(foods[i]);
}
}
};

到目前为止一切顺利。现在的问题是,FoodAnimal 有许多不同的派生类。 Food 有派生类 FruitMeatAnimal 有派生类 Carnivore食草动物Herbivore 只能接受Fruit 作为食物偏好,Carnivore 只能接受Meat

class Fruit : public Food
{
};
class Meat : public Food
{
};
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);
}
};

我可以在不违反里氏替换原则的情况下为此创建类继承吗?虽然我在这个问题中使用了 C++,但我也欢迎特定于 Java 的答案。

最佳答案

首先,您的setFoodPreference 必须有失败 选项。这让 setFoodPreference 接受一个 Food* 并具有设置食物偏好或失败的后置条件。

动态转换也可能是 LSP 的失败,但如果您将类型不变量设置得足够模糊,从技术上讲,这并不是失败。

通常,dynamic_cast 表示传递的参数类型及其属性不足以判断参数是否具有某些属性。

原则上,setFoodPreference(Food*) 应该根据传入的参数必须具有哪些 Food* 属性来指定,以便设置成功; Food* 的动态类型不是 Food* 属性。

因此:LSP 指出 Food 的任何子类都必须遵守所有 Food 不变量。 Animal 也是如此。您可以通过使不变量模糊和方法的行为不可预测来避免违反 LSP;基本上是说“它可能因不明原因而失败”。这……不是很令人满意。

现在,您可以退后一步,确定您的Food* 的动态类型是Food*部分界面;这使得界面宽泛得离谱,并且 mock 了 LSP。

LSP 的要点是您可以推理 Food* 而无需考虑其子类类型;它们是“作为食物的运作方式”。您的代码与子类类型紧密绑定(bind),从而绕过了 LSP 点。

有很多方法可以解决这个问题。如果 Food 有一个枚举说明它是什么食物,而你永远不会动态转换为 Meat 而是询问 Food 它是否是肉,你避免它。现在您可以根据 Food 的界面指定 setFoodPreference 的行为。

关于java - Liskov 替换原则和多重层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36315970/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com