必要时可以违反Composition Over Inheritance吗?

问题描述 投票:1回答:1

我有一组课程:


// This is #included from another header file
// I don't want to inherit this, because it ain't my code
class DrawableObject;

class Animal {
    DrawableObject obj;
    // Does not define run() or swim()
};

class Cat : public Animal {
    void run() { /* Calls obj.setPosition() and other stuff */ }
};

class Dog : public Animal {
    void run() { /* Calls obj.setPosition() and other stuff */ }
    void swim() { /* Calls obj.setPosition() and other stuff */ }
};

class Dolphin : public Animal {
    void swim() { /* Calls obj.setPosition() and other stuff */ }
};

在这里,Dog::run()Cat::run()碰巧使用完全相同的代码,Dog::swim()Dolphin::swim()也使用相同的代码。我不想在整个地方复制粘贴代码,而是想重复使用它。明智的解决方案似乎是在基类(Animal)和具体类(Cat/Dog/Dolphin)之间添加中间子类:

       /-> RunnableAnimal --> Cat
       |                  \
Animal-|                  |-> Dog
       |                  /
       \-> SwimmableAnimal -> Dolphin

问题是:我是否反对“超越继承的构成”规则?如果是这样,这是完全没问题的,还是有办法在实现代码重用的同时坚持CoI?

注意:我不需要或不需要多态 - 当我使用run()时,我总是使用具体(Cat/Dog/Sloth)类而不是基础Animal类来调用它。

c++ inheritance composition
1个回答
4
投票

更好的继承模式:

          /–––––––––– Cat
         /          /
        /    Runner
       /            \
Animal –––––––––––––– Dog
       \            /
        \    Swimmer
         \          \
          \–––––––––– Dolphin

您可以避免使用方法引入的菱形图案。

您可以在需要时在动物中聚合Runner / Swimmer实例,而不是继承,让动物的功能只委托给成员。

关于你的模型只是一个小问题:它并没有真正反映现实,实际上,猫,虽然不喜欢水,也是相当不错的游泳运动员......

编辑:由于RunnerSwimmer需要访问Animal的成员:你可以通过curiously recurring template pattern提供这个;在下面添加了一个演示

class Animal
{
protected:
    int n = 7;
};

template <typename T>
class Swimmer
{
public:
    void swim()
    {
        std::cout << static_cast<T*>(this)->n << std::endl;
    }
};

class Dolphin : public Animal, public Swimmer<Dolphin>
{
    friend class Swimmer; // n is protected!
    // (alternatively, Swimmer might already be a friend of Animal)
};


int main(int argc, char* argv[])
{
    Dolphin d;
    d.swim();

    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.