Questa struttura del codice è utile in qualche modo?

8

Recentemente sono stato gettato in un progetto di applicazione Web Java e ho incontrato un certo numero di classi che seguono questo tipo di formato:

public class MyThingy {
   private final int p1;
   private final String p2;
   …

   public MyThingy (int p1, String p2, …) {
      this.p1 = p1;
      this.p2 = p2;
      …
   }

   public static void doSomething(int p1, String p2, …) throws Throwable     {
      final MyThingy myThingy = new MyThingy(p1, p2, …);
      myThingy.execute();
   }

   private void execute() throws Throwable {
      //do stuff 
   }
}

Sembra che questo potrebbe essere realizzato con il seguente codice, che per me sembra molto più facile da leggere.

public class MyThingy {

   public static void doSomething (int p1, String p2, …) throws Throwable {
      //do stuff 
   }

}

L'unico vantaggio possibile che posso vedere dal farlo è che se dovessi suddividere execute () in pezzi più piccoli, tutti potrebbero condividere i parametri iniziali senza doverli esplicitamente passare in giro. Ma questo forse giova al codificatore pigro, poiché diventa difficile per il lettore dire quali metodi hanno bisogno di quali parametri e quando i valori possono essere cambiati (come le variabili globali).

C'è qualcosa che mi manca? Threading, performance?

Modifica: Avrei dovuto menzionare, anche se il costruttore è pubblico, non viene chiamato. L'unico utilizzo è il seguente:

MyThingy.doSomething(p1, p2...);

A parte questo, di per sé problematico per i test, non vedo alcun motivo per non mettere la logica di execute () direttamente in doSomething (). Anche se dovessimo sbarazzarci della funzione statica, il costruttore non ha ancora senso per me; Penso che i parametri dovrebbero essere passati direttamente al metodo che li utilizzerà.

    
posta Mishelle 04.11.2015 - 22:16
fonte

4 risposte

2

Penso che la tua intuizione su questo problema sia giusta.

  • Quello che abbiamo qui è un metodo semplice (in questo caso, statico) la cui implementazione è stata "scomposta" in una classe.
  • La tecnica del "metodo come classe" riduce il numero di variabili che devi passare esplicitamente in giro, mentre in realtà oscuri il modo in cui i dati fluiscono usando quelle che sono, nello spirito, variabili "globali".
  • Nessuno di questi è in realtà nello spirito di OO, poiché l'istanza è throwaway e il suo stato è effimero.
  • Eppure, questo è uno schema comune, specialmente nei libri introduttivi di Java e potrebbe essere stato nelle menti dei designer Java (che ha introdotto molti modi per dichiarare le classi, apparentemente per aiutare questo uso).

Quindi dovresti usarlo ?

  • Certo, a volte.

In effetti, il problema non è solo "metodi come classi". Nelle classi normali, potresti essere tentato di creare campi che non mantengono invocazioni intermedie tra i metodi pubblici. Sono utilizzati solo per evitare il passaggio di parametri tra metodi privati. In passato, ho cercato di evitarlo a tutti i costi, ma poi mi sono reso conto che anche le lunghe liste di parametri fanno schifo.

Cerco di evitare le " pure " classi di metodi "perché penso che arrivino con un sacco di bagagli mentali (così tanto potenziale potenziale). (Mi appoggio anche ai campi usa e getta nelle classi regolari.) Ma se c'è un sacco di variabili da passare in giro, la vittoria sulla pulizia del codice potrebbe valerne la pena.

Cerco di usare le classi quando c'è un punto in esso, e infatti di solito è facile immaginarne una. Forse in futuro estendere la classe con ulteriori implementazioni. Forse l'istanza può essere pensata come un oggetto funzione che vorresti inizializzare e trasmettere. E poi, la classe non è più una "classe del metodo" pseudo-OO.

    
risposta data 05.11.2015 - 10:44
fonte
6

L'ulteriore riferimento indiretto tramite la chiamata al metodo statico separa i dubbi su come viene creato un oggetto dal codice che utilizza l'oggetto. Quello che hai qui è qualcosa di molto simile a un semplice metodo di fabbrica (in realtà non restituisce l'oggetto, ma l'indirezione della creazione dell'oggetto è la stessa).

Questo può essere utile se è necessario controllare il tipo di oggetto che viene creato. In questo semplice esempio non c'è alcuna decisione da prendere, ma sarebbe facile aggiungere quella logica.

Ciò che il codice statico significa per i chiamanti è "Ho bisogno di fare qualcosa con questo stato ma non so come delegare". Il metodo statico può quindi delegare all'implementazione corretta in base all'oggetto fornito.

Forse durante l'esecuzione di un test unitario viene utilizzato un oggetto fittizio. Forse in base ai parametri è possibile scambiare un oggetto diverso che implementa un algoritmo diverso per fare tutto ciò che deve fare. Localizzando quel codice in una posizione, la decisione può essere presa in un posto anziché arbitrariamente in molti.

Dato il modo in cui la tua domanda è formulata e il fatto che nessuna decisione di costruzione sia stata presa nei metodi statici, ho la sensazione che questo potrebbe essere solo un caso di sovraingegnerizzazione. La maggior parte del codice non ha bisogno di delegare a una fabbrica. Il fatto che continui a incontrare codice come questo che non prende ogni decisione, come mi aspetterei da un metodo statico simile a quello di fabbrica, mi dice che qualcuno ha letto GoF book e ha funzionato.

    
risposta data 04.11.2015 - 23:04
fonte
0

Bene, se il tuo secondo esempio (che mostra il codice completo ) ha il seguente aspetto:

public static void doSomething(int p1, String p2, …) throws Throwable     {
      final MyThingy myThingy = new MyThingy(p1, p2, …);
      myThingy.execute();
   }

quindi hai ancora bisogno del costruttore

public MyThingy (int p1, String p2, …) {
      this.p1 = p1;
      this.p2 = p2;
      …
   }

che a sua volta imposta

   private final int p1;
   private final String p2;

e ora sei tornato dove hai iniziato.

Potresti, ovviamente, solo eliminare il costruttore e andare con getter e setter, invece

private final int p1;
private final String p2;

public void SetP1(int p1)
{
    this.p1 = p1;
}

public int GetP1()
{
    return p1;
}
// repeat for p2

... ma questo complicherà la tua chiamata al metodo statico, poiché ora avrai bisogno di più linee di codice per chiamare i setter prima di chiamare il tuo metodo statico, dove sarebbe bastata una singola linea che usasse la chiamata del costruttore.

Naturalmente, funziona solo se le variabili membro non sono final . Pertanto, hai ancora bisogno del costruttore.

    
risposta data 04.11.2015 - 22:30
fonte
0

Di solito una classe ha molti metodi di istanza e una volta creato l'oggetto, l'implementazione di execute può sfruttare tutti questi metodi di istanza. Se rifiuti di creare un oggetto, tutti questi metodi di istanza sono inutili.

    
risposta data 05.11.2015 - 00:16
fonte

Leggi altre domande sui tag