IMHO puoi fare questo, e ci possono essere situazioni in cui questa è la soluzione più semplice (ad esempio, quando ti è vietato cambiare l'interfaccia in alcun modo), ma alla mia esperienza più approccio SOLID è non per rendere la parte getLastExecutionOutput
dell'interfaccia della strategia. Ciò eliminerebbe del tutto la necessità della classe AbstractStrategy
.
Guarda invece il luogo (tipicamente un metodo template ) dove viene chiamato execute
. Probabilmente è una buona idea lasciare che il chiamante memorizzi l'ultima uscita da sola. L'intera idea del modello strategico è di separare le parti di "strategie diverse" dalle parti che sono non differenti in ogni strategia. Ciò rende più semplici gli oggetti strategici, con una migliore distribuzione delle responsabilità. L'interfaccia nel tuo esempio assegna ad ogni oggetto strategico due responsabilità per lo più indipendenti (oltre alla responsabilità di fornire il codice di strategia individuale, ha la responsabilità aggiuntiva di memorizzare nell'ultimo output in cache) e quindi implica una violazione del SRP .
Supponendo che tu non possa cambiare l'interfaccia e debba implementare i metodi precedenti: in questo caso prenderei in considerazione l'idea di implementarla in un modo leggermente diverso (non sono un ragazzo Java, quindi ti prego di perdonarmi eventuali errori sintattici):
public abstract class CachingStrategy implements Strategy {
private Output lastOutput;
public Output execute(Input input)
{
lastOutput = executeInternal(input);
return lastOutput;
}
protected abstract Output executeInternal(Input input);
public Output getLastExecutionOutput()
{
return lastOutput;
}
}
Ora, quando deriva da questa classe, devi implementare executeInternal
invece di execute
in ogni classe figlia. La differenza notevole è che le classi figlio ora non devono più fornire il codice per impostare correttamente lastOutput
, questa responsabilità è ora completamente nella classe CachingStrategy
.
Come ho scritto sopra, penso che questa sia solo la seconda soluzione migliore. Quando si hanno due soluzioni quasi uguali, una con l'uso dell'ereditarietà e l'altra senza, come regola generale, provare prima a usare quella senza ereditarietà. L'utilizzo dell'ereditarietà qui non sembra essere un grosso problema a prima vista, ma pensa a cosa potrebbe accadere quando ottieni requisiti aggiuntivi "per tutte le strategie" come "attivare un evento ogni volta che viene chiamato execute", "memorizzare nella cache non solo l'ultimo output , ma anche l'ultimo input ", e così via. La semplice soluzione sembra quindi implementare tutte queste nuove funzionalità nella tua "classe base comune", che potrebbe finire in un grande ingordigia.