Il modo più umano per ordinare le definizioni dei metodi di classe?

28

In ogni definizione di classe data, ho visto le definizioni dei metodi ordinate in vari modi: alfabetico, cronologico basato sull'uso più comune, alfabetico raggruppato per visibilità, alfabetico con getter e setter raggruppati, ecc. Quando inizio a scrivere un nuova classe, tendo a digitare tutto, poi riordino quando ho finito di scrivere l'intera classe. Su quella nota, ho tre domande:

  1. L'ordine è importante?
  2. Esiste un "miglior" ordine?
  3. Immagino che non ci sia, quindi quali sono i pro e i contro delle diverse strategie di ordinazione?
posta Johntron 24.05.2013 - 18:08
fonte

4 risposte

35

In alcuni linguaggi di programmazione, l'ordine è importante perché non puoi utilizzare le cose fino a dopo che sono state dichiarate. Ma a parte questo, per la maggior parte delle lingue non ha importanza per il compilatore. Quindi, ti rimane che conta per gli umani.

La mia citazione preferita di Martin Fowler è: Any fool can write code that a computer can understand. Good programmers write code that humans can understand. Quindi direi che l'ordine della tua classe dovrebbe dipendere da ciò che rende facile per gli umani capire.

Personalmente preferisco il trattamento step-down che Bob Martin dà nel suo libro Clean Code . Le variabili membro nella parte superiore della classe, quindi i costruttori, quindi tutti gli altri metodi. E tu ordini i metodi per essere vicini insieme a come sono usati all'interno della classe (piuttosto che mettere tutto in modo pubblico poi privato e poi protetto). La chiama minimizzando la "distanza verticale" o qualcosa del genere (non avere il libro su di me al momento).

Modifica

L'idea di base della "distanza verticale" è che vuoi evitare di far saltare le persone attorno al tuo codice sorgente solo per capirlo. Se le cose sono collegate, dovrebbero essere più vicine. Le cose non correlate possono essere più distanti.

Il capitolo 5 di Pulisci codice (ottimo libro, btw) entra in una tonnellata di dettagli su come Mr. Martin suggerisce di ordinare il codice. Suggerisce che il codice di lettura dovrebbe funzionare come leggere un articolo di giornale: i dettagli di alto livello vengono prima (in alto) e ottieni maggiori dettagli mentre leggi. Dice: "Se una funzione chiama un'altra, dovrebbero essere chiuse verticalmente e il chiamante dovrebbe essere al di sopra della chiamata, se possibile." Inoltre, i concetti correlati dovrebbero essere vicini.

Ecco un esempio forzato che non funziona in molti modi (scarsa progettazione OO, mai usare double per soldi) ma illustra l'idea:

public class Employee {
  ...
  public String getEmployeeId() { return employeeId; }
  public String getFirstName() { return firstName; }
  public String getLastName() { return lastName; }

  public double calculatePaycheck() {
    double pay = getSalary() / PAY_PERIODS_PER_YEAR;
    if (isEligibleForBonus()) {
      pay += calculateBonus();
    }
    return pay;
  }

  private double getSalary() { ... }

  private boolean isEligibleForBonus() {
    return (isFullTimeEmployee() && didCompleteBonusObjectives());
  }

  public boolean isFullTimeEmployee() { ... }
  private boolean didCompleteBonusObjectives() { ... }
  private double calculateBonus() { ... }
}

I metodi sono ordinati in modo che siano vicini a quelli che li chiamano, procedendo dall'alto verso il basso. Se avessimo messo tutti i metodi private al di sotto di public , allora dovresti fare ancora un salto per seguire il flusso del programma.

getFirstName e getLastName sono concettualmente correlati (e getEmployeeId probabilmente lo è anche), quindi sono vicini. Potremmo spostarli tutti verso il basso, ma non vorremmo vedere getFirstName nella parte superiore e getLastName nella parte inferiore.

Speriamo che questo ti dia l'idea di base. Se ti interessa questo tipo di cose, ti consiglio vivamente di leggere Clean Code .

    
risposta data 24.05.2013 - 18:21
fonte
1

In genere ordino i miei metodi per relazione e ordine di utilizzo.

Partecipa a una lezione di networking, raggrupperò tutti i metodi TCP insieme, quindi tutti i metodi UDP insieme. Il TCP interno avrò il metodo di setup come primo, forse invierò un secondo messaggio e chiuderò il socket tcp come terzo.

Ovviamente non tutte le classi si adatteranno a quel modello, ma questo è il mio flusso di lavoro generale.

Lo faccio in questo modo per il debug più di ogni altra cosa, quando ho un problema e voglio saltare al metodo, non penso a come è scritto, penso a cosa è responsabile e andare a quello sezione.

In questo modo, in particolare, ha senso che una terza parte visualizzi / utilizzi il tuo codice raggruppato e seguirà l'ordine in cui viene utilizzato, quindi il codice che scriverà con la classe seguirà la stessa struttura della classe.

Per quanto riguarda?

per la leggibilità, sicuramente.

diverso da quello non proprio, solo nei casi in cui certe lingue non puoi chiamare il metodo a meno che non sia definito sopra dove è chiamato ecc.

    
risposta data 24.05.2013 - 18:21
fonte
0

Idealmente, le tue classi sono così piccole che non importa. Se hai solo una dozzina di metodi e il tuo editor o IDE supporta la piegatura, non hai alcun problema, perché l'intero elenco di metodi si adatta a 12 righe.

In caso contrario, la distinzione di primo livello dovrebbe essere pubblica o privata. Elenca prima i metodi pubblici: questi sono quelli che la gente cercherà di più, perché definiscono il modo in cui la tua classe si interfaccia con il resto della base di codice.

Quindi, all'interno di ciascuno di questi, ha più senso raggruppare i metodi in base alla funzionalità: costruttori e distruttori in un blocco, getter / setter in un altro, overload dell'operatore, metodi statici e il resto del gruppo. In C ++, però, mi piace mantenere operator= vicino ai costruttori, perché è strettamente correlato al costruttore di copie, e anche perché voglio essere in grado di individuare rapidamente se tutti (o nessuno) di default ctor, copy ctor, operatore = e dtor esistono.

    
risposta data 24.05.2013 - 22:39
fonte
-1

tl; dr

Solo se la lingua in cui lavori richiede un ordine specifico. A parte questo, l'ordine spetta a te. Scegli un sistema coerente e ragionevole e cerca di seguirlo il più possibile.

1 . Does order matter?

Solo se la lingua che stai lavorando deve avere una funzione definita in precedenza nel file rispetto a dove è stata chiamata, come in questo esempio:

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

riceverai un errore perché chiami funcB() prima di usarlo. Penso che questo sia un problema in PL / SQL e probabilmente anche in C, ma puoi avere dichiarazioni in avanti come:

void funcB();

void funcA()
{
   funcB();
}

void funcB()
{
   //do something interesting...
}

Questa è l'unica situazione a cui riesco a pensare dove, se l'ordine è "sbagliato", non sarai neanche in grado di compilare.

Altrimenti puoi sempre riordinarli come vuoi. Probabilmente potresti persino scrivere uno strumento per farlo (se non riesci a trovarne uno là fuori).

2 . Is there a "best" order?

Se la lingua / l'ambiente non ha requisiti di ordinazione, l'ordine "migliore" è quello che funziona meglio per tu . Per me, mi piace avere tutti i getter / setter insieme, di solito all'inizio della classe (ma dopo i costruttori / inizializzatori statici), quindi i metodi privati, quindi protetti, quindi pubblici. In ogni gruppo basato su scope di solito c'è l'ordine no , anche se i metodi sovraccarichi cerco di stare insieme, in ordine di numero di parametri. Cerco anche di mantenere insieme i metodi con le funzionalità correlate, anche se a volte devo interrompere il mio ordinamento basato su ambito per farlo; e a volte provando a mantenere l'ordinamento basato sull'ambito si interrompe group-by-function. E il mio IDE può darmi una vista in schema alfabetico, quindi va anche bene. ;)

Alcune lingue, come C #, hanno la capacità di raggruppare il codice in " regioni " che non hanno alcun effetto sulla compilazione ma potrebbero rendere più semplice mantenere le funzioni correlate insieme, quindi nasconderlo / visualizzarle con l'IDE. Come indicato da MainMa , alcuni considerano questa pratica negativa. Ho visto esempi positivi e negativi di regioni utilizzate in questo modo, quindi se stai andando in questo modo, fai attenzione.

    
risposta data 24.05.2013 - 18:17
fonte

Leggi altre domande sui tag