当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《C++类设计,为每个不同的行为提供多个接口》经验,为你挑选了1个好方法。

这是我的第一篇文章,所以要善良.这是我最近得到的一个面试问题,但我在搜索后找不到答案(谷歌,C++ FAQ等).

存在具有行为b1()的接口I1.有A,B,C三个等级.所有这些类都通过覆盖b1()来实现接口I1.存在第四类D,其具有在接口I1中定义的行为(b1)和额外行为b2

问题是你如何设计课程D.

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

采访者同意解决方案,但询问如果将来有新的行为出现的新课程,我们将如何处理

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

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

PS:经过认真思考后,我认为答案可能在于使用设计模式,但看看常见的设计模式,我找不到任何与此问题相符的模式

编辑1:我有更多的问题和澄清,所以在这里编辑帖子,不确定这是否正确或我需要发布这个作为我自己的问题的答案.

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

@Nawaz的Vistor模式的例子非常有用,但我想这只是访问者提出的原始问题的一个特例.@Alexandre正确地指出了这里的场景.

让我解释一下这个的另一个方面.当我们谈论行为时,我们需要基于它们对它们进行分组

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

2)与小组相关的不常见或非常特殊的行为(这是反直觉的)例如:仅仅为了争论,考虑一个组成音乐的家伙(我知道这个例子不完美)

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 :-) )

因此,如果我们在设计应用程序之前知道机器人的完整列表,我们可以提供更好的设计,但是我们如何设计何时按上述顺序按顺序引入每种新类型.我的观点是,我们知道机器人具有某些行为或特征,但是当以后必须引入不常见的特征(如自我修复,机器人机器人)时,我们该怎么办?

谢谢.



1> Nawaz..:

我认为面试官期待你谈论访客模式.

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

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

访客模式

以下是访问者模式的一个简单实现:

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

截至目前,该类Dude只有两种行为,即LaughDudeBehavior,WalkDudeBehavior但由于它是一个访问者模式,您可以添加任意数量的行为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  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;
}

现在没有内存泄漏.:-)


为什么不在accept中使用引用,仍然为您提供多态行为,这意味着您不必管理堆分配的临时值,可以只是dude-> accept(EatDudeBehavior());
推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有