Modello di progettazione di strategia modificata


11

Ho iniziato a esaminare i modelli di design di recente e una cosa che sto codificando si adatterebbe perfettamente al modello di strategia, fatta eccezione per una piccola differenza.

In sostanza, alcuni (ma non tutti) dei miei algoritmi, hanno bisogno di un parametro aggiuntivo o due passati a loro.

Quindi ne avrò bisogno

  • passare loro un parametro extra quando invoco il loro metodo di calcolo

o

  • memorizzarli come variabili all'interno della classe ConcreteAlgorithm ed essere in grado di aggiornarli prima di chiamare l'algoritmo.

Esiste un modello di progettazione per questa esigenza / Come potrei implementarlo mentre aderisco al modello di strategia?

Ho preso in considerazione il passaggio dell'oggetto client a tutti gli algoritmi e la memorizzazione delle variabili al suo interno, per poi usarlo solo quando il particolare algoritmo ne ha bisogno. Tuttavia, penso che sia ingombrante e sconfigge il punto del modello di strategia.

Giusto per essere chiaro, sto implementando in Java, e quindi non ho il lusso di parametri opzionali (che lo risolverebbero bene).


I parametri opzionali come in C ++ non risolverebbero nulla, poiché sono solo una scorciatoia per la definizione di più metodi sovraccarichi.
maaartinus,

Farei del mio meglio per evitare di memorizzare i parametri aggiuntivi da qualche parte dove ho dovuto modificarli prima dell'uso. In questo modo rendi ConcreteAlgorithm con stato, quindi non può essere passato facilmente ad altri metodi o thread. Inoltre, è troppo facile dimenticare di impostare i parametri.
maaartinus,

Risposte:


5

Samuel, è possibile incapsulare il parametro che ciascuna strategia prende in una classe comune e quindi estendere quella classe Parametro comune per aggiungere più comportamento di cui alcune delle tue strategie hanno bisogno?

Per esempio

StrategyParameter //Base strategy parameter that most of the strategies need
        ^
        |
        |
SpecialStrategyParameter // will be used for strategies that need more parameter

E quindi, definire la gerarchia di strategia come:

Interface MyStrategy {
   void myStrategyMethod(StrategyParameter parameter);
}

class MyNormalStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

chiama la strategia di cui sopra come: myNormalStrategyInstance.myStrategyMethod(strategyParameter);

class MySpecializedStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

chiama la strategia sopra passando SpecialStrategyParameteristanza invece come:mySpecializedStrategy.myStrategyMethod(specialStrategyParameter);

Si prega di aggiornare se qualcosa non è chiaro. Sarà felice di spiegare / chiarire.


2
-1 richiede downcast, interrompe l'incapsulamento del design. Sebbene si tratti di un miglioramento del design nella domanda, ci sono modi migliori per scuoiare questo gatto.
tallseth

@tallseth Vedo anche downcast. Ma non vedo modi migliori. Potresti indicare una soluzione migliore? Un articolo o qualcosa del genere?
Narek,

Attualmente si. @ Jordão ha la risposta che preferirei, in base ai dettagli che abbiamo nella domanda. Questa risposta gioca ai punti di forza del modello di strategia. Se seguissimo l'approccio in questa risposta, vorrei avere StrategyParametertutti i parametri possibili, proprio come un DTO. Alcune implementazioni della strategia potrebbero ignorarle. In alcuni casi, questo è l'approccio migliore. Il contesto è re per questo tipo di problemi.
tallseth,

4

Devi chiarire la tua strategia .

Tutto dipende da come usi i tuoi algoritmi. Affinché la classe del cliente utilizzi in modo intercambiabile diverse implementazioni di strategia, tutte devono avere un'astrazione comune . Se non seguono la stessa interfaccia, forse ciò di cui hai bisogno sono diverse astrazioni .

Ho usato strategie configurabili in precedenza, dove si parametrizzano le classi concrete sulla costruzione:

interface Strategy {
  int calculate();
}

class ConcreteStrategyThatNeedsAParameter implements Strategy {
  private final int param;
  public ConcreteStrategyThatNeedsAParameter(int param) {
    this.param = param;
  }
  public int calculate() { 
    // uses param...
  }
}

Ora, qualcuno deve ancora creare un'istanza di questa classe e passarla al tuo client. Ma il tuo cliente deve solo conoscere l' Strategyinterfaccia.

Funziona anche se il tuo metodo di strategia accetta parametri, ma il tuo client conosce questi parametri e li passa a tutte le implementazioni con cui funziona.


Il client è quello con il contesto per fornire il parametro.
Andyczerwonka,

1

Fintanto che la firma è chiaramente definita sull'interfaccia, è comunque conforme al modello di strategia.

I motivi scritti sono la forma più semplice in assoluto che mostra ancora il comportamento previsto, quindi puoi abbellirli fintanto che mantieni l'intento originale. Questo ovviamente presuppone che tu voglia seguire il modello. Non ha senso usare uno schema se non si adatta, o semplicemente perché è lì, ma nel tuo caso penso che tu stia bene.


0

estendendo la risposta sopra fornita da peakit - puoi usare l'astrazione. Sto usando il codice di Peakit qui -

Interface MyStrategy { abstract void myStrategyMethod (parametro StrategyParameter); }

class MyNormalStrategy estende MyStrategy {override pubblico void myStrategyMethod (parametro StrategyParameter) {// implementa la logica qui}}

class MySpecializedStrategy estende MyStrategy {override pubblico void myStrategyMethod (parametro StrategyParameter, ExtraStrategyParameter extraParameter) {// implementa la logica qui} }

Se capisco correttamente la tua domanda, hai voluto passare un parametro aggiuntivo a determinati algoritmi, giusto? Per favore fatemi sapere se questo è quello che stavate cercando?


0

Se si esamina il libro dei modelli di progettazione, non è di per sé sbagliato che esista qualche SimpleStrategy che utilizza meno o nessuno dei parametri passati o che i parametri sono un moltiplicatore uguale per tutti. La scelta del design qui è se questo ti fa male in termini di elaborazione extra che finisce per non essere utilizzata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.