gpt4 book ai didi

C++ 类设计为每个不同的行为提供多个接口(interface)

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:17:02 25 4
gpt4 key购买 nike

这是我的第一篇文章,所以请善待。这是我最近得到的一个面试问题,但我在搜索(google、C++FAQ 等)后找不到答案。

有一个行为 b1() 的接口(interface) I1。有3个类A,B,C。所有这些类都通过覆盖 b1() 来实现接口(interface) I1。有第四个类 D,它具有在接口(interface) I1 中定义的行为 (b1) 和一个额外的行为 b2

问题是你如何设计D类。

我的答案是创建另一个接口(interface) I2,它定义行为 b2() 并通过覆盖 b1() 和 b2() 使类 D 实现 I1 和 I2(C++ 中的多重继承)

面试官同意这个解决方案,但问如果将来出现具有新行为的新类(class),我们将如何处理

我只能考虑添加更多接口(interface)(I3、I4 等)并进行多重继承,但我知道在这里您最终会得到大量具有相应接口(interface)的派生类

面试官似乎期待更好的解决方案,但他没有透露答案。我很想知道这里的专家将如何解决这个设计问题。

PS:经过深思熟虑,我认为答案可能在于使用设计模式,但是查看常见的设计模式我找不到与此问题匹配的任何模式

编辑 1:我有更多问题和说明,因此在此处编辑帖子,不确定这是否正确,或者我需要将其发布为我自己问题的答案。

首先让我感谢 @Nawaz、@Alexandre 和 @Sjoerd 的宝贵意见。我刚刚开始学习 C++/设计模式中的设计方面,所以请原谅我对这个主题的无知。

@Nawaz 的 Vistor 模式示例确实很有帮助,但我想这只是面试官提出的原始问题的一个特例。 @Alexandre 正确地指出了这里的场景。

让我解释一下这件事的另一个方面。
当我们谈论行为时,我们需要根据

1) 与一组对象或对象相关的常见行为。 (这是直观的或可以像在现实世界中一样观察到的)
例如:Dude 的行为(以@Nawaz 为例)-我走路、吃饭、学习等

2)与群体相关的不常见或非常奇特的行为(这是违反直觉的)
例如:只是为了争论,考虑一个作曲的 Dude(我知道这个例子并不完美)

3) 与团体完全无关的行为。我想不出一个例子,但我的观点是让我们说出于某种奇怪的原因我们需要给对象这种行为。

所以我认为访问者模式可以解决 1) 中的问题,但我怀疑它不会用于 2) 和 3)。

以 IDude 为例,我们需要进行以下更改才能创建一个可以创作音乐的 Dude。

    class IComposerBehavior;

class IComposer
{
public:
virtual ~IComposer() {}
virtual void accept(IComposerBehavior *behaviour) = 0 ;
};

class IComposerBehavior
{
public:
virtual ~IComposerBehavior() {}
virtual void visit(IComposer * ) = 0;
};

class Dude : public IDude, public IComposer
{
public:
virtual void accept(IDudeBehavior *behaviour)
{
behaviour->visit(this);
}
virtual void accept(IComposerBehavior *behaviour)
{
behaviour->visit(this);
}
};

class SymphonyComposerBehavior : public IComposerBehavior
{
public:
virtual void visit(IComposer *dude) { cout << "Dude is composing a symphony" << endl; }
};

同样,我们还需要更改客户端代码以考虑 SymphonyComposerBehavior。

所以基本上我们最终改变了 Dude 类代码和客户端代码,这抵消了模式的影响。

我认为面试官问的是新的行为,不能放在之前确定的一组相关行为中。所以在这种情况下,即使类是固定的,访问者模式是否可以像@Alexandre 指出的那样解决?

让我在这里举一个例子(不知道这是否是代表问题的正确例子)。假设我需要为机器人制造公司设计一个应用程序。随着需求逐渐增加
- Initially We are only producing Toy Robots
- Then Human helper Robots
- Then Self Healing Robots (would just correct itself when defective)
- Then Humanoid Robots
- Then machine Robots (that are not human like but as a substitute for any machine you can think of) . I have deliberately put this here even though its place should be before with a correct evolution scheme.
- finally Humanoid Robots with life (atleast we can dream :-) )

因此,如果我们在设计应用程序之前知道机器人的完整列表,我们就可以提出更好的设计,
但是,当每个新类型按上述顺序依次引入时,我们如何设计。我的意思是我们知道机器人具有某些行为或特征,但是当稍后必须引入不常见的功能时(例如自我修复,机器机器人)我们该怎么做?

谢谢。

最佳答案

我认为面试官希望你谈论访问者模式。

是的,访问者模式允许您将新行为添加到现有的类结构中,而无需进一步向结构中添加/派生类/接口(interface)。所有这一切只需要您实现行为,而访问者模式允许您将此行为添加到类的结构中。

阅读这个维基条目;它解释了模式:

  • Visitor pattern

  • 这是访问者模式的一种简单实现:
    class IDudeBehavior;

    class IDude
    {
    public:
    virtual ~IDude() {}
    virtual void accept(IDudeBehavior *behaviour) = 0 ;
    };

    class IDudeBehavior
    {
    public:
    virtual ~IDudeBehavior() {}
    virtual void visit(IDude * ) = 0;
    };

    class Dude : public IDude
    {
    public:
    virtual void accept(IDudeBehavior *behaviour)
    {
    behaviour->visit(this);
    }
    };

    class LaughDudeBehavior : public IDudeBehavior
    {
    public:
    virtual void visit(IDude *dude) { cout << "Dude is Laughing" << endl; }
    };

    class WalkDudeBehavior : public IDudeBehavior
    {
    public:
    virtual void visit(IDude *dude) { cout << "Dude is Walking" << endl; }
    };
    int main() {
    IDude *dude = new Dude();
    dude->accept(new LaughDudeBehavior());
    dude->accept(new WalkDudeBehavior());
    return 0;
    }

    在线演示: http://ideone.com/Kqqdt

    截至目前,类(class) Dude只有两个行为,即 LaughDudeBehaviorWalkDudeBehavior但由于它是访问者模式,您可以向 Dude 添加任意数量的行为, 不编辑类 Dude .例如,如果要添加 EatDudeBehaviorStudyCplusCplusDudeBehavior ,那么你只需要实现 IDudeBehavior作为:
    class EatDudeBehavior : public IDudeBehavior
    {
    public:
    virtual void visit(IDude *dude) { cout << "Dude is Eating" << endl; }
    };

    class StudyCplusCplusDudeBehavior : public IDudeBehavior
    {
    public:
    virtual void visit(IDude *dude) { cout << "Dude is Studying C++" << endl; }
    };

    然后你需要接受这些行为:
    dude->accept(new EatDudeBehavior ()); 
    dude->accept(new StudyCplusCplusDudeBehavior ());

    添加这些新行为后的演示: http://ideone.com/9jdEv

    避免内存泄漏

    上面的代码有一个问题。一切看起来都很好,只是它会泄漏内存。该程序使用 new 创建了许多类实例。 ,但它从未使用 delete 解除分配它们.所以你也需要考虑这个问题。

    内存泄漏可以很容易地修复,如下所示:
    int main() {
    IDude *dude = new Dude();

    std::vector<IDudeBehavior*> behaviours;
    behaviours.push_back(new LaughDudeBehavior());
    behaviours.push_back(new WalkDudeBehavior());
    behaviours.push_back(new EatDudeBehavior());
    behaviours.push_back(new StudyCplusCplusDudeBehavior());

    for(size_t i = 0 ; i < behaviours.size() ; i++ )
    dude->accept(behaviours[i]);

    //deallcation of memory!
    for(size_t i = 0 ; i < behaviours.size() ; i++ )
    delete behaviours[i];
    delete dude;
    return 0;
    }

    No memory leak now . :-)

    关于C++ 类设计为每个不同的行为提供多个接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6965703/

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