Come evitare un sovraccarico eccessivo dei metodi?

10

Abbiamo un sacco di posti nel codice sorgente della nostra applicazione, in cui una classe ha molti metodi con gli stessi nomi e parametri diversi. Questi metodi hanno sempre tutti i parametri di un metodo "precedente" più uno.

È il risultato di una lunga evoluzione (codice legacy) e questo modo di pensare (credo):

" C'è un metodo M che fa la cosa A. Devo fare A + B. OK, lo so ... Aggiungerò un nuovo parametro a M, creerò un nuovo metodo per quello, sposta il codice da M al nuovo metodo con un altro parametro, fai A + B e chiama il nuovo metodo da M con un valore predefinito del nuovo parametro. "

Ecco un esempio (in linguaggio simile a Java):

class DocumentHome {

  (...)

  public Document createDocument(String name) {
    // just calls another method with default value of its parameter
    return createDocument(name, -1);
  }

  public Document createDocument(String name, int minPagesCount) {
    // just calls another method with default value of its parameter
    return createDocument(name, minPagesCount, false);
  }

  public Document createDocument(String name, int minPagesCount, boolean firstPageBlank) {
    // just calls another method with default value of its parameter
    return createDocument(name, minPagesCount, false, "");
  }

  public Document createDocument(String name, int minPagesCount, boolean firstPageBlank, String title) {
    // here the real work gets done
    (...)
  }

  (...)
}

Mi sembra che sia sbagliato. Non solo non possiamo continuare ad aggiungere nuovi parametri come questo per sempre, ma il codice è difficile da estendere / modificare a causa di tutte le dipendenze tra i metodi.

Ecco alcuni modi per farlo meglio:

  1. Introdurre un oggetto parametro:

    class DocumentCreationParams {
    
      String name;
      int minPagesCount;
      boolean firstPageBlank;
      String title;
    
      (...)
    }
    
    class DokumentHome {
    
      public Document createDocument(DocumentCreationParams p) {
        // here the real work gets done
        (...)
      }
    }
    
  2. Imposta i parametri sull'oggetto DocumentHome prima di chiamare createDocument()

      @In
      DocumentHome dh = null;
    
      (...)
    
      dh.setName(...);
      dh.setMinPagesCount(...);
      dh.setFirstPageBlank(...);
    
      Document newDocument = dh.createDocument();
    
  3. Separa il lavoro in diversi metodi e chiamalo secondo necessità:

      @In
      DocumentHome dh = null;
    
      Document newDocument = dh.createDocument();
      dh.changeName(newDocument, "name");
      dh.addFirstBlankPage(newDocument);
      dh.changeMinPagesCount(new Document, 10);
    

Le mie domande:

  1. Il problema descritto è davvero un problema?
  2. Cosa ne pensi delle soluzioni suggerite? Quale preferiresti (in base alla tua esperienza)?
  3. Riesci a pensare ad altre soluzioni?
posta Ytus 07.04.2014 - 10:52
fonte

4 risposte

15

Forse prova il builder modello ? (nota: risultato Google abbastanza casuale:)

var document = new DocumentBuilder()
                   .FirstPageBlank()
                   .Name("doc1final(2).doc")
                   .MinimumNumberOfPages(4)
                   .Build();

Non posso dare una panoramica completa del motivo per cui preferisco il builder sulle opzioni che offri, ma hai identificato un grosso problema con un sacco di codice. Se pensi di aver bisogno di più di due parametri per un metodo probabilmente hai il tuo codice strutturato in modo errato (e qualcuno ne sosterrebbe uno!).

Il problema con un oggetto params è (a meno che l'oggetto che tu crei sia in qualche modo reale) semplicemente spinga il problema su un livello, e finisci con un cluster di parametri non correlati che formano l''oggetto'.

I tuoi altri tentativi mi sembrano come se qualcuno cercasse il modello di builder, ma non ci arrivava:)

    
risposta data 07.04.2014 - 11:23
fonte
1

L'utilizzo di un oggetto parametro è un buon modo per evitare (eccessivo) sovraccarico dei metodi:

  • pulisce il codice
  • separa i dati dalla funzionalità
  • rende il codice più gestibile

Tuttavia, non andrei troppo lontano con esso.

Avere un sovraccarico qui e non c'è una brutta cosa. È supportato dal linguaggio di programmazione, quindi usalo a tuo vantaggio.

Non ero a conoscenza del modello di builder, ma l'ho usato "per caso" in alcune occasioni. Lo stesso vale qui: non esagerare. Il codice nel tuo esempio potrebbe trarne vantaggio, ma impiegare molto tempo per implementarlo per ogni metodo che ha un singolo metodo di sovraccarico non è molto efficiente.

Solo i miei 2 centesimi.

    
risposta data 08.04.2014 - 16:26
fonte
0

Onestamente non vedo un grosso problema con il codice. In C # e C ++ puoi usare parametri opzionali, sarebbe un'alternativa, ma per quanto ne so Java non supporta quel tipo di parametri.

In C # potresti rendere privati tutti gli overload e un metodo con parametri facoltativi è pubblico per chiamare il materiale.

Per rispondere alla tua domanda parte 2, vorrei prendere l'oggetto parametro o anche un dizionario / HashMap.

Così:

class DokumentHome {

  public Document createDocument(Map<string, object> params) {
    if (params.containsKey("yourkey")) {
       // do that
    }
    // here the real work gets done
    (...)
  }
}

Come disclaimer, sono prima un programmatore C # e JavaScript e poi un programmatore Java.

    
risposta data 07.04.2014 - 13:11
fonte
0

Penso che questo sia un buon candidato per il modello di builder. Il pattern Builder è utile quando vuoi creare oggetti dello stesso tipo, ma con rappresentazioni differenti.

Nel tuo caso, avrei un builder con i seguenti metodi:

SetTitle (Document document) { ... }
SetFirstPageBlank (Document document) { ... }
SetMinimumPageCount (Document document) { ... }

Puoi quindi utilizzare il builder nel modo seguente:

_builder.SetTitle(document);
_builder.SetFirstPageBlank(document);

Sulla nota a margine, non mi importa di alcuni semplici overload - che diavolo, .NET framework li usa dappertutto con gli helper HTML. Tuttavia, rivalutarei cosa sto facendo se dovessi passare più di due parametri per ogni metodo.

    
risposta data 07.04.2014 - 13:49
fonte

Leggi altre domande sui tag