【问题标题】:Is Polymorphism worth an increase in coupling?多态性是否值得增加耦合?
【发布时间】:2009-01-08 21:54:12
【问题描述】:

我正在编写一个简单的游戏来学习获得更多 C++ 经验,并且我有一个想法,我觉得多态性几乎 有效,但没有。在这个游戏中,Party 相当线性地穿过Map,但偶尔会在路上遇到Fork。叉子(基本上)是一个std::vector<location*>。最初我打算在Party 成员函数中编写如下代码:

if(!CurrLocation->fork_.empty())
   // Loop through forks and show options to the player, go where s/he wants
else
  (CurrLocation++)

但我想知道以下的一些变体是否会更好:

CurrLocation = CurrLocation->getNext();

Fork 实际上是从 Location 派生的,并重载了一些新函数 getNext()。但在后一种情况下,location(一个低级结构)必须是向用户呈现消息而不是“传递这个备份”的那个,我不觉得这很优雅,因为它结合了@ 987654330@转UserInterface::*

你的意见?

【问题讨论】:

    标签: c++ polymorphism coupling


    【解决方案1】:

    所有问题都可以通过添加一个间接级别来解决。我会使用您建议的变体,并通过允许 getNext 接受解析方向选择的对象来将 Location 与 Party 分离。这是一个示例(未经测试):

    class Location; 
    
    class IDirectionChooser
    {
    public:
      virtual bool ShouldIGoThisWay(Location & way) = 0;
    };
    
    class Location
    {
    public:
      virtual Location * GetNext(IDirectionChooser & chooser)
      {
        return nextLocation;
      }
    
      virtual Describe();
    private:
      Location * nextLocation;
    };
    
    class Fork : public Location
    {
    public:
      virtual Location * GetNext(IDirectionChooser & chooser)
      {
        for (int i = 0; i < locations.size(); i++)
          if (chooser.ShouldIGoThisWay(*locations[i]))
            return locations[i];
      }
      virtual Describe();
    private:
      vector<Location *> locations;
    };
    
    class Party : public IDirectionChooser
    {
    public:
      void Move()
      {
        currentLocation = currentLocation->GetNext(GetDirectionChooser());
      }
    
      virtual IDirectionChooser & GetDirectionChooser() { return *this; }
    
      virtual bool ShouldIGoThisWay(Location & way)
      {
        way.Describe();
        cout << "Do you want to go that way? y/n" << endl;
    
        char ans;
        cin >> ans;
        return ans == 'y';
      }
    };
    

    【讨论】:

    • 对 IInterface 命名法感到遗憾。否则完美。
    • 真的吗?为什么?我们在我工作的地方使用它。如果有充分的理由不使用它,请告诉我,我会编辑答案。
    • 不错!我建议添加到 Party: "virtual IDirectionChooser& getDirectionChooser() { return *this; }",并让 Move() 调用它而不是直接使用 *this——这将使子类能够使用不同的(例如外部)IDirectionChooser通过仅覆盖该方法来实现。
    • 根据 j_random_hacker 的 cmets 更新。
    【解决方案2】:

    您应该使用多态性,只要它有意义并简化您的设计。你不应该仅仅因为它存在并且有一个花哨的名字就使用它。如果它确实使您的设计更简单,那么值得耦合。

    正确和简单应该是每个设计决策的最终目标。

    【讨论】:

      【解决方案3】:

      我认为您自己发现了这些问题,并且可以根据您对系统其余部分的了解或此处提供的更多详细信息来解决问题。

      如前所述:

      1. 应该使用多态性来简化设计 - 在这种情况下它会这样做,所以很好发现。
      2. 您遇到了耦合问题 - 再次发现,耦合可能会导致以后出现问题。然而,这对我说的是你的方式 应用多态性可能不是最好的方法。
      3. 接口编程应该允许您隐藏系统如何组合在一起的内部细节,从而减少耦合。

      【讨论】:

        【解决方案4】:

        多态不会带来更大的耦合,我认为它们是不同的问题。

        事实上,如果您正在对接口进行编程并遵循控制模式的一般反转,那么您将导致更少或零耦合。

        在你的例子中,我没有看到位置是如何与 UserInterface 耦合的?

        如果是这种情况,是否可以通过 UserInterface 和 Location 之间的另一个抽象级别(例如 LocationViewAdapter)来消除耦合?

        【讨论】:

        • 继承会增加耦合,多态性往往依赖于继承。
        • 没错,但是如果您将基类注入到您的方法中,那么这是减少耦合的方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多