Opzioni di refactoring: più metodi nella stessa classe o in classi separate

6

abbiamo alcune API che verranno chiamate dal client A, B, C o D

Codice corrente

doSomething(String client){

if (client.equals("A")){
...
}
else if (client.equals("B")){
...
}

Rifattorizzazione proposta 1

separare in più metodi e fare in modo che ogni cliente chiami il metodo dedicato come

doSomethingForClientA()

doSomethingForClientB()

abbiamo bisogno di questo perché internamente ogni metodo chiamerà altri metodi privati definiti nella stessa classe

Rifattorizzazione proposta 2

Utilizza lo schema di strategia (o modello) e separalo in più classi per i client da chiamare

la chiamata al metodo dal client rimane

doSomething()

Quale approccio è migliore a lungo termine? C'è qualche modello di progettazione per aiutare con l'opzione 1? o una terza opzione?

    
posta shinynewbike 19.07.2012 - 07:35
fonte

5 risposte

7

Il refactoring proposto 2 è migliore a lungo termine.

Ciò consentirà di estendere funzionalità aggiuntive per tipi di client aggiuntivi (imprevisti) in un secondo momento, senza modificare parti di codice testate, per client già esistenti.

    
risposta data 19.07.2012 - 08:34
fonte
2

Questa è davvero una buona domanda con l'analisi presentata!

Se cerchi maintainable and extensible code , ovviamente utilizza l'opzione 2! . È uno degli esempi in cui viene applicato il principio di inversione di dipendenza.

Come riferimento suggerirei di consultare i principi S.O.L.I.D. . Inoltre, c'è una buona risposta su una domanda simile - Programmazione dei principi SOLID

    
risposta data 19.07.2012 - 13:59
fonte
1

[estensione del mio commento precedente]

Puoi spostare questi codici speciali alle classi wrapper assegnate ai tipi di client, crearli quando il cliente entra e utilizzare le loro funzioni.

interface ClientWrapper {
  void doSomething();
}

class ClientWrapperForA implements ClientWrapper {
  void doSomething() {
    // do that something for client A
  }
}

È possibile creare ClientWrapperFactory configurabile, singleton, la configurazione è una mappa con coppie ["A" - "wrapper.class.name.for.clientA"] e crea l'istanza chiamando Class.forName (cfgMap.get ( "A")). NewInstance (), memorizza l'istanza del wrapper corrente nel contesto della sessione (o "ottiene" tutto il tempo, e usa la creazione lenta) - Suppongo che tu parli di un'applicazione web. Aggiungere un nuovo client significa solo estendere questa mappa con un nuovo elemento e creare la classe wrapper appropriata.

    
risposta data 19.07.2012 - 10:32
fonte
1

La seconda opzione è migliore. Usa il modello di strategia. Ovviamente puoi usare ancora usa doSomethingForClientX() nelle funzioni private se non riesci a pensare ad un nome migliore. Utilizzare il modello di modello solo se la sequenza di operazioni (chiamate di funzioni private) rimane la stessa.

    
risposta data 19.07.2012 - 10:12
fonte
0

C'è qualcosa che manca nella tua domanda: è solo l'unico metodo doSomething che deve gestire il client A e il client B in modo diverso, o ci sono altri metodi simili? Se c'è solo una differenza, allora puoi farla franca con un'istruzione if o forse un'istruzione switch, quindi l'originale non è male.

Non esporrei doSomethingForClientA () e doSomethingForClientB (). È possibile avere questi due come metodi privati e chiamare quello giusto dal metodo doSomething. Potresti non farlo in questo modo se il codice per ogni caso è uguale al 95%.

Una volta che decidi di usare più classi, mostri che non hai sentito parlare del modello delegato. È qui che hai una classe e inserisci un oggetto delegato responsabile della gestione delle differenze tra diversi client. Ovviamente diversi oggetti delegati per diversi client. Sia che si utilizzi il modello delegato o più classi, si ottiene l'enorme vantaggio che non è necessario passare le informazioni sul client in giro. Il che è molto utile se il chiamante non è il client e non sa in realtà quale tipo di client viene utilizzato.

    
risposta data 16.05.2017 - 23:02
fonte

Leggi altre domande sui tag