2010-08-03 17 views
5

Ho una classe contiene 10 metodi che stanno facendo quasi le stesse cose a parte un evento chiave. Due esempi sono i seguenti:rimuovere la duplicazione


Public String ATypeOperation(String pin, String amount){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildATypeRequest(pin, amount); 
    doAfterStuff(); 
} 
 


Public String BTypeOperation(String name, String sex, String age){ 
    doSomething(); 
    doMoreStuff(); 
    requestBuilder.buildBTypeRequest(name, sex, age); 
    doAfterStuff(); 
} 
 

Come si può vedere dai metodi di cui sopra, sono simili a parte chiamare diversi metodi forniti da requestBuilder. Anche il resto 8 è simile. C'è molto codice duplicato qui. Sento che c'è un modo migliore per implementarlo, ma non so come. Tutte le idee e i suggerimenti sono apprezzati.

Grazie, Sarah

+1

La richiesta è effettivamente utilizzata nel metodo? – helpermethod

+0

@Helper Sì, lo è. Puoi dire che è usato in doAfterSuff(); – sarahTheButterFly

risposta

5

usare qualcosa di simile RequestBuilder, che accetta tutti questi tipi di parametri:

public RequestBuilder { 
    // setters and getters for all properties 

    public Request build() { 
     doStuff(); 
     Request request = new Request(this); 
     doAfterStuff(); 
     return request; 
    } 
} 

e poi

new RequestBuilder().setAge(age).setName(name).build(); 
+0

Ho una domanda qui. Quando un cliente che usa il RequestBuilder(), come fa a sapere quali parametri deve impostare? Ad esempio, nel mio post, ad esempio, dovrei chiedere al cliente di scegliere di impostare 2 dei 5 parametri possibili. Come possiamo essere sicuri che il client non imposti un parametro errato? – sarahTheButterFly

+0

imposta quello che vuole (ha 'a portata di mano'). Se la combinazione non è sufficiente, lanciare un'eccezione. – Bozho

+0

Si passano i parametri obbligatori nel costruttore RequestBuilder e qualsiasi parametro facoltativo mediante chiamate di metodo aggiuntive prima di chiamare build. Questo è ciò che il costruttore è fatto per: molti parametri opzionali (per ridurre i costruttori telescopici) @bozo si dovrebbe davvero impostare i parametri obbligatori nel costruttore costruttore – atamanroman

2
interface RequestBuilder { 
    void doStuff(params); 
} 

public RequestBuilder getARequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public RequestBuilder getBRequestBuilder() { 
    return new RequestBuilder() { 
    void doStuff(params) { 
     // impl.details 
    } 
    } 
}  

public String buildRequest(yourParams, RequestBuilder builder){ 
    doBefore(); 
    builder.doStuff(yourParams); 
    doAfter(); 
} 

penso che questo è chiamato il modello Strategy. Assomiglia molto allo schema Command ma poiché si incapsula un algoritmo sembra essere Strategia :)

Ciò che Bozho suggerisce è il modello Builder.

Ti consiglio di scorrere tra a list of patterns un po 'di tempo o di acquistare i modelli Primo capo. Lettura davvero divertente

+0

Non ero sicuro se questo fosse un modello di comando o strategia. Il tuo disaccoppiamento è un algo (strategia) ma d'altra parte questa è chiaramente una chiamata al metodo incapsulato (comando). Forse qualcuno può dire perché è il suo modello. Direi il suo comando anche se il metodo è chiamato immediatamente :) – atamanroman

+0

@fielding Immagino che sia l'intento che conta di più. Ma io uso solo i pattern (a volte senza sapere che è un pattern :) e non sono un tipo di ragazzo teorico. – extraneon

1

Si potrebbe passare l'oggetto costruttore di un metodo buildRequest generico. Dal momento che non solo l'algoritmo ma anche gli argomenti variano, li metto nel costruttore. Non penso che questo è una bella soluzione, ma ho voluto mostrare un modello di comando qui: D (Extraneon mostrò come scindere params e di comando)

// call somewhere in the code: 
    Builder b = new BTypeBuilder(); 
    b.age = "20"; b.sex = "female"; b.name = "eve"; 
    String res = buildRequest(b); 

    Public String buildRequest(Builder builder) 
    { 
     doSomething(); 
     doMoreStuff(); 
     builder.build(); 
     doAfterStuff(); 
    } 

    // Command pattern 
    class BTypeBuilder implements Builder 
    { 
     String name, age, sex; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    class ATypeBuilder implements Builder 
    { 
     String pin, amount; 

     // Constructor here 

     void build() 
     { 
      // Do your stuff here 
     } 
    } 

    public interface Builder 
    { 
     void build(); 
    } 
+0

Mi piace la tua soluzione. Ma penso che esponga BTypeBuilder() a un client. Il che significa che il cliente deve conoscere tutti i diversi tipi di costruttori. Non è questo "accoppiamento stretto"? – sarahTheButterFly

+0

Potresti introdurre una sorta di Builder-Factory. Un metodo di fabbrica statico dovrebbe essere sufficiente e nasconde tutti i diversi costruttori. Dipende da cosa stai facendo. Se questo è parte della tua API pubblica, lo sforzo è ragionevole. Se non è così, non andrei così lontano. Btw: Se ti piace una risposta, invitalo;) – atamanroman

+0

Haha ... hai appena messo in votazione il tuo post! Grazie per aver risposto alla mia domanda. ;) – sarahTheButterFly

0

In aggiunta alle altre risposte, questo potrebbe essere utile anche per voi (se si vuole solo il plugin il vostro metodo, non usare i parametri per la 'prima' e 'dopo' metodi)

interface Function0<R> { 
    R apply(); 
} 

public void performOperation(Function0<Void> operation) { 
    doSomething(); 
    doBeforeStuff(); 
    operation.apply(); 
    doAfterStuff(); 

} 

allora si potrebbe usare in questo modo,

final RequestBuilder builder = new RequestBuilder(); 
    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildATypeRequest("1234", "2445"); 
      return null; 
     } 
    }); 

    performOperation(new Function0<Void>() { 
     public Void apply() { 
      builder.buildBTypeRequest("1234", "2445", "1234"); 
      return null; 
     } 
    }); 
0

Invece di inviare una lunga param lista eter basta premere tutti i parametri in una mappa e inviare quella mappa come argomento.

+0

Hmmm..Se la dimensione dell'elenco dei parametri è inferiore a 6 (o 4?), Allora è ok. In realtà è meglio che spingerli in una mappa, penso. Come fa il tuo utente a sapere cosa inserire nella mappa? – sarahTheButterFly

+0

Da dove viene questo aiuto? Devi aggiungere una nuova convalida perché non puoi più dirlo se la mappa contiene oggetti adatti. Sarebbe meglio introdurre una sorta di classe Persona, che potrebbe raggruppare nome, sesso ed età. Se hai molti parametri, prova a introdurre fabbriche o costruttori. Ma questo non ha nulla a che fare con la domanda iniziale. – atamanroman

Problemi correlati