2010-01-14 18 views
10

Abbiamo un insieme di classi che derivano da un set comune di interfacce tali cheme codifica in un angolo

IFoo-> BasicFoo, ReverseFoo, ForwardFoo 
IBar -> UpBar, DownBar, SidewaysBar 
IYelp -> Yip, Yap, Yup 

in cui il costruttore per gli sguardi del Foo come Foo(IBar, IYelp) Questi elementi sono utilizzati in tutto il progetto.

Esiste un'altra classe che ha un metodo la cui firma è public double CalcSomething(IFoo, IAnotherClass) che viene applicata a un certo punto a ogni Foo. Abbiamo ricevuto una richiesta dall'alto che una particolare composizione di un oggetto, ad esempio uno BasicFoo(UpBar,Yip), utilizza un algoritmo diverso da quello trovato in CalcSomething.

Il mio primo istinto era di cambiare l'interfaccia di IFoo in modo da spostare la logica al livello di classe Foo, cambiare il costruttore in Foo(IBar, IYelp, IStrategy) e poi inserire gli oggetti di Foo in questa logica. Sfortunatamente ci è stato anche detto che la progettazione dell'architettura stabilisce che non ci sono dipendenze tra IFoo, le sue implementazioni e IAnotherClass. Sono irremovibili su questo.

Ok, certo, allora ho pensato di usare un modello di visitatore ma ... come? L'intero punto di fare la composizione era in modo che nessun'altra classe potesse vedere i dettagli di implementazione. Riflessione per guardare dentro gli oggetti, rompendo totalmente l'incapsulamento? Oh diavolo no.

Quindi sono venuto qui perché sono in perdita. Qualcuno ha qualche suggerimento su come possiamo trattare un caso speciale di una delle composizioni senza modificare la composizione o interrompere l'incapsulamento? Deve esserci una soluzione semplice che sto guardando troppo.

Modifica:

Inizio offensivo rimosso. Modificato "gestito appositamente" in un significato più descrittivo.

+9

Non fallisce mai - quando una domanda inizia cercando di giustificare la mancata pubblicazione del codice, il tentativo risultante di evitare di postare il codice rende quasi impossibile capire l'intero mess. – delfuego

+0

rimosso la parte offendente – wheaties

+0

Puoi chiarire cosa intendi con "trattato in modo speciale"? –

risposta

3

Un CalculationFactory che sceglie un algoritmo appropriato in base al tipo di IFoo che fornisci risolverebbe il problema (al costo di un condizionale):

interface ICalcSomethingStrategy { 
    public double CalcSomething(IFoo, IAnotherClass); 
} 

CalcSomethingStrategyFactory { 
    ICalcSomethingStrategy CreateCalcSomethingStrategy(IFoo foo) { 
     // I'm not sure whether this is the idiomatic java way to check types D: 
     if (foo.Bar instanceof UpBar && foo instanceof Yip) { 
      return new UnusualCalcSomethingStrategy(); 
     } else { 
      return new StandardCalcSomethingStrategy(); 
     } 
    } 
} 
+0

Stavamo solo discutendo se questo potesse portare a compimento quello che stiamo cercando di fare. Non vediamo nessun altro modo di usare la riflessione per arrivare al fondo di come dividere le cose. – wheaties

+0

Sebbene l'accoppiamento sia più stretto, si potrebbe considerare questo in termini di fornire ai client un contesto dal quale chiamare 'calcSomething()': http://en.wikipedia.org/wiki/Strategy_pattern#Java – trashgod

1

Non c'è modo per calcSomething per evitare di avere le conoscenze necessarie per fare il comportamento "speciale", ma a parte questo, puoi mantenere la maggior parte del tuo incapsulamento in questo modo.

Creare un'interfaccia marker IQualifyForSpecialTreatment che estende IFoo. Estendi BasicFoo a SpecialBasicFoo e implementa IQualifyForSpecialTreatment.


    interface IQualifyForSpecialTreatment extends IFoo { 
    } 
    class SpecialBasicFoo extends BasicFoo implements IQualifyForSpecialTreatment { 
     ... 
    } 

È quindi possibile aggiungere un altro sapore del calcSomething:


    calcSomething (IQualifyForSpecialTreatment foo, IAnotherClass whatever) { 
     ... perform "special" variant of calculation 
    } 
    calcSomething (IFoo foo, IAnotherClass whatever) { 
     ... perform "normal" variant of calculation 
    } 
3

Nello spirito di BACIO vorrei aggiungere un metodo isSpecial() per IFoo, e l'uso che per decidere quale algoritmo da utilizzare in CalcSomething().

Questo presuppone che questo sia l'unico caso speciale.

+0

+1 concordato, il L'approccio di fabbrica che ho suggerito è probabilmente più pesante di quanto dovrebbe essere se si tratta di un caso unico. –

+0

+1 anzi. Semplice, ordinato e sufficiente. Se viene violato il presupposto del "solo caso speciale", isSpecial() potrebbe essere refactored per restituire un valore di "algoritmo di calcolo da applicare". – CPerkins