Search code examples
c++polymorphismcoupling

Is Polymorphism worth an increase in coupling?


I'm writing a simplistic game to learn get some more C++ experience, and I have an idea where I feel polymorphism almost works, but doesn't. In this game, the Party moves fairly linearly through a Map, but can occasionally encounter a Fork in the road. A fork is (basically) an std::vector<location*>.Originally I was going to code something like the following into the a Party member function:

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

But I was wondering if some variant of the following might be better:

CurrLocation = CurrLocation->getNext();

With Fork actually being derived from Location, and overloading some new function getNext(). But in the latter case, the location (a low level structure) would have to be the one to present the message to the user instead of "passing this back up", which I don't feel is elegant as it couples location to UserInterface::*.

Your opinions?


Solution

  • All problems can be solved by adding a level of indirection. I would use your suggested variant, and decouple Location from Party by allowing getNext to accept an object that resolves directional choices. Here is an example (untested):

    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';
      }
    };