我在这里滥用继承吗?什么是最佳实践替代/模式?

tri*_*ta2 6 c++ polymorphism inheritance

大编辑

因此,在收集了所有人的反馈意见,并按照Zack的建议冥想XY问题后,我决定添加另一个代码示例,该示例说明了我正在努力完成的事情(即"X"),而不是询问我的" Y".


所以,现在我们正在与汽车工作,我已经添加了5抽象类:ICar,ICarFeatures,ICarParts,ICarMaker,ICarFixer.所有这些接口都将包装或使用第三方库提供的特定于技术的复杂对象,具体取决于接口背后的派生类.这些接口将智能地管理复杂库对象的生命周期.

我的用例是FordCar类.在这个例子中,我用了福特库访问班FordFeatureImpl,FordPartsImplFordCarImpl.这是代码:

class ICar {
public:
    ICar(void) {}
    virtual ~ICar(void) {}
};

class FordCar : public ICar {
public:
    ICar(void) {}
    ~FordCar(void) {}
    FordCarImpl* _carImpl;
};

class ICarFeatures {
public:
    ICarFeatures(void) {}
    virtual ~ICarFeatures(void) {}
    virtual void addFeature(UserInput feature) = 0;
};

class FordCarFeatures : public ICarFeatures{
public:
    FordCarFeatures(void) {}
    virtual ~FordCarFeatures(void) {}
    virtual void addFeature(UserInput feature){

        //extract useful information out of feature, ie:
        std::string name = feature.name;
        int value = feature.value;
        _fordFeature->specialAddFeatureMethod(name, value);
    }

    FordFeatureImpl* _fordFeature;
};

class ICarParts {
public:
    ICarParts(void) {}
    virtual ~ICarParts(void) {}
    virtual void addPart(UserInput part) = 0;
};

class FordCarParts :public ICarParts{
public:
    FordCarParts(void) {}
    virtual ~FordCarParts(void) {}
    virtual void addPart(UserInput part) {

        //extract useful information out of part, ie:
        std::string name = part.name;
        std::string dimensions = part.dimensions;
        _fordParts->specialAddPartMethod(name, dimensions);
    }
    FordPartsImpl* _fordParts;
};

class ICarMaker {
public:
    ICarMaker(void) {}
    virtual ~ICarMaker(void) {}
    virtual ICar* makeCar(ICarFeatures* features, ICarParts* parts) = 0;
};

class FordCarMaker {
public:
    FordCarMaker(void) {}
    virtual ~FordCarMaker(void) {}
    virtual ICar* makeCar(ICarFeatures* features, ICarParts* parts){

        FordFeatureImpl* fordFeatures = dynamic_cast<FordFeatureImpl*>(features);
        FordPartsImpl* fordParts = dynamic_cast<FordPartsImpl*>(parts);

        FordCar* fordCar = customFordMakerFunction(fordFeatures, fordParts);

        return dynamic_cast<ICar*>(fordCar);
    }

    FordCar* customFordMakerFunction(FordFeatureImpl* fordFeatures, FordPartsImpl* fordParts) {

        FordCar* fordCar =  new FordCar;

        fordCar->_carImpl->specialFeatureMethod(fordFeatures);
        fordCar->_carImpl->specialPartsMethod(fordParts);

        return fordCar;
    }
};


class ICarFixer {
public:
    ICarFixer(void) {}
    virtual ~ICarFixer(void) {}
    virtual void fixCar(ICar* car, ICarParts* parts) = 0;
};


class FordCarFixer {
public:
    FordCarFixer(void) {}
    virtual ~FordCarFixer(void) {}
    virtual void fixCar(ICar* car, ICarParts* parts) {

        FordCar* fordCar = dynamic_cast<FordCar*>(car);
        FordPartsImpl* fordParts = dynamic_cast<FordPartsImpl*>(parts);

        customFordFixerFunction(fordCar, fordParts);


}

customFordFixerFunction(FordCar* fordCar, FordPartsImpl* fordParts){
    fordCar->_carImpl->specialRepairMethod(fordParts);
}
};
Run Code Online (Sandbox Code Playgroud)

请注意,我必须使用动态强制转换来访问抽象接口中特定于技术的对象.这就是让我觉得我滥用继承并激怒我最初问这个问题的原因.

这是我的最终目标:

UserInput userInput = getUserInput(); //just a configuration file ie XML/YAML
CarType carType = userInput.getCarType();

ICarParts* carParts = CarPartFactory::makeFrom(carType);
carParts->addPart(userInput);

ICarFeatures* carFeatures = CarFeaturesFactory::makeFrom(carType);
carFeatures->addFeature(userInput);

ICarMaker* carMaker = CarMakerFactory::makeFrom(carType);
ICar* car = carMaker->makeCar(carFeatures, carParts);

UserInput repairSpecs = getUserInput();
ICarParts* replacementParts = CarPartFactory::makeFrom(carType);
replacementParts->addPart(repairSpecs);

ICarFixer* carFixer = CarFixerFactory::makeFrom(carType);
carFixer->fixCar(car, replacementParts);
Run Code Online (Sandbox Code Playgroud)

也许现在你们都对我正在尝试做的事情有了更好的理解,也许我可以改进.

我正在尝试使用基类的指针来表示派生(即Ford)类,但派生类包含FordPartsImpl其他派生类(即FordCarFixer需要a FordCarFordPartsImplobject)所需的特定对象(即).这需要我使用动态转换来将指针从基础向下转换到其各自的派生类,以便我可以访问这些特定的Ford对象.

Cla*_*dgz 4

我的问题是:我在这里滥用继承吗?我试图在工人和对象之间建立多对多的关系。我觉得我做错了什么,因为拥有一个 Object 系列类,它实际上除了保存数据之外什么也不做,并使 ObjectWorker 类必须动态转换对象才能访问内部。

这不是滥用继承...这是滥用继承

class CSNode:public CNode, public IMvcSubject, public CBaseLink,
         public CBaseVarObserver,public CBaseDataExchange, public CBaseVarOwner
Run Code Online (Sandbox Code Playgroud)

其中那些带有 C 前缀的人有巨大的实现

不仅如此...标头有超过 300 行声明。

所以不......你现在没有滥用继承权。

但我刚刚向您展示的这个类是侵蚀的产物。我确信 Node 一开始就是一个闪亮的灯塔和多态性,能够在行为和节点之间智能切换。

现在它已经变成了海怪、巨蛾、克苏鲁本身,只用它的幻象就试图咀嚼我的内脏。

留意这个自由人,留意我的忠告,当心你的多态性可能会变成什么样子。

否则,这很好,继承的一个很好的用途,我认为是尿布中的架构。

如果我只想有一个 work() 方法,我还有什么其他选择?

单一工作方法...您可以尝试:

  • 基于策略的设计,其中策略具有模型的实现
  • 每个类都使用的函数“work”
  • 函子!在将使用的每个类中实例化

但你的继承似乎是正确的,每个人都会使用的单一方法。

还有一件事......我只是要把这个维基链接留在这里

或者也许只是复制粘贴 wiki C++ 代码...这与您的非常相似:

#include <iostream>
#include <string>
 
template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy
{
    using OutputPolicy::print;
    using LanguagePolicy::message;
 
public:
    // Behaviour method
    void run() const
    {
        // Two policy methods
        print(message());
    }
};
 
class OutputPolicyWriteToCout
{
protected:
    template<typename MessageType>
    void print(MessageType const &message) const
    {
        std::cout << message << std::endl;
    }
};
 
class LanguagePolicyEnglish
{
protected:
    std::string message() const
    {
        return "Hello, World!";
    }
};
 
class LanguagePolicyGerman
{
protected:
    std::string message() const
    {
        return "Hallo Welt!";
    }
};
 
int main()
{
    /* Example 1 */
    typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyEnglish> HelloWorldEnglish;
 
    HelloWorldEnglish hello_world;
    hello_world.run(); // prints "Hello, World!"
 
    /* Example 2 
     * Does the same, but uses another language policy */
    typedef HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> HelloWorldGerman;
 
    HelloWorldGerman hello_world2;
    hello_world2.run(); // prints "Hallo Welt!"
}
Run Code Online (Sandbox Code Playgroud)

更重要的问题是

您将如何在 StringWorker 中使用 Int 对象?

您当前的实现将无法处理该问题

有政策就有可能。

可能的对象有哪些?

帮助您定义是否需要这种行为

记住,不要用猎枪杀鸡

也许你的模型永远不会随着时间的推移而真正改变。