Полиморфизм стоит увеличения сцепления?

Я пишу упрощенную игру, чтобы научиться получать больше опыта в 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 (структура низкого уровня) должна была бы быть тем, чтобы представить сообщение пользователю вместо того, чтобы "передавать это обратно", что я не считаю элегантным, поскольку оно объединяет location в UserInterface::*,

Ваши мнения?

4 ответа

Решение

Все проблемы могут быть решены путем добавления уровня косвенности. Я бы использовал предложенный вами вариант и отделил Location от Party, позволив getNext принять объект, который разрешает выбор направления. Вот пример (не проверено):

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

Вы должны использовать полиморфизм, если он имеет смысл и упрощает ваш дизайн. Вы не должны использовать его только потому, что он существует и имеет причудливое имя. Если это делает ваш дизайн проще, то оно того стоит.

Правильность и простота должны быть конечной целью каждого дизайнерского решения.

Я думаю, что вы сами определили проблемы и, возможно, сможете решить их с помощью своих знаний об остальной части системы или нескольких подробностей, которые мы рассмотрим здесь.

Как уже упоминалось:

  1. Полиморфизм следует использовать, чтобы упростить конструкцию - что он и сделал бы в этом случае, так что это хорошо видно.
  2. У вас есть проблема с муфтой - опять хорошо заметна, муфта может привести к проблемам в дальнейшем. Однако это говорит мне о том, что способ применения полиморфизма может быть не лучшим.
  3. Программирование на интерфейсах должно позволить вам скрыть внутренние детали того, как система собрана, и таким образом уменьшить связь.

Полиморфизм не дает большей связи, я думаю, что это отдельные вопросы.

Фактически, если вы программируете интерфейсы и следуете общей инверсии шаблонов управления, то это приведет к меньшему или нулевому соединению.

В вашем примере я не вижу, как местоположение связано с UserInterface?

Если это так, может ли связь быть удалена через другой уровень абстракции между UserInterface и Location, такой как LocationViewAdapter?

Другие вопросы по тегам