Il polimorfismo vale un aumento nell'accoppiamento?
-
06-07-2019 - |
Domanda
Sto scrivendo un gioco semplicistico per imparare a fare un po 'più di esperienza in C ++, e ho un'idea di dove sento che il polimorfismo quasi funziona, ma non lo fa. In questo gioco, il Party
si sposta in modo abbastanza lineare attraverso un Map
, ma occasionalmente può incontrare un Fork
sulla strada. Un fork è (sostanzialmente) un std::vector<location*>
. Inizialmente stavo per scrivere qualcosa come il seguente nella funzione getNext()
membro:
if(!CurrLocation->fork_.empty())
// Loop through forks and show options to the player, go where s/he wants
else
(CurrLocation++)
Ma mi chiedevo se qualche variante di quanto segue potesse essere migliore:
CurrLocation = CurrLocation->getNext();
Con Fork effettivamente derivato da Location e sovraccarico di alcune nuove funzioni location
. Ma in quest'ultimo caso, UserInterface::*
(una struttura di basso livello) dovrebbe essere quella per presentare il messaggio all'utente anziché & Quot; passando questo backup & Quot ;, che non la sensazione è elegante in quanto si accoppia da <=> a <=>.
Le tue opinioni?
Soluzione
Tutti i problemi possono essere risolti aggiungendo un livello di riferimento indiretto. Vorrei usare la tua variante suggerita e disaccoppiare Location da Party consentendo a getNext di accettare un oggetto che risolva le scelte direzionali. Ecco un esempio (non testato):
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';
}
};
Altri suggerimenti
Dovresti usare il polimorfismo purché abbia senso e semplifichi il tuo design. Non dovresti usarlo solo perché esiste e ha un nome di fantasia. Se semplifica la progettazione, vale la pena accoppiare.
La correttezza e la semplicità dovrebbero essere l'obiettivo finale di ogni decisione progettuale.
Penso che tu abbia individuato i problemi da solo e che probabilmente tu possa risolverli con la tua conoscenza del resto del sistema o qualche altro dettaglio qui che possiamo esaminare.
Come è stato menzionato:
- Il polimorfismo dovrebbe essere usato per semplificare il design, cosa che farebbe in questo caso, così ben individuato.
- Si riscontra un problema con l'accoppiamento: di nuovo ben individuato, l'accoppiamento può causare problemi in seguito. Tuttavia, ciò che mi dice è il modo in cui sei applicare il polimorfismo potrebbe non essere il modo migliore.
- La programmazione alle interfacce dovrebbe consentire di nascondere i dettagli interni di come il sistema è stato messo insieme e ridurre così l'accoppiamento.
Il polimorfismo non si presta a un maggiore accoppiamento, penso che siano questioni separate.
In effetti, se si sta programmando interfacce e seguendo l'inversione generale dei modelli di controllo, si otterrà un accoppiamento minore o nullo.
Nel tuo esempio, non vedo come la posizione è accoppiata a UserInterface?
In questo caso, è possibile rimuovere l'accoppiamento attraverso un altro livello di astrazione tra UserInterface e Location, come LocationViewAdapter?