2009-05-06 13 views
24

Questi i due approcci:Costruttore con tutte le proprietà di classe o costruttore predefinito con setter?

  • costruttore con tutte le proprietà della classe

Pro: devo mettere un numero esatto di tipi di parametri così se faccio un errore del compilatore mi avverte (a proposito, c'è un modo per prevenire il problema di avere erroneamente commutato due interi nella lista dei parametri?)

Contro: se ho molte proprietà la linea di istanziazione può diventare davvero lunga e potrebbe estendersi su due o più linee

  • setter e il costruttore vuoto di default

Pro: posso vedere chiaramente quello che sto impostando, quindi se sto facendo qualcosa di sbagliato che posso individuare non appena sto scrivendo di esso (Non riesco a fare l'errore precedente di commutare due variabili dello stesso tipo)

Contro: l'istanziazione di un oggetto con molte proprietà potrebbe richiedere più righe (non so se questo è davvero un problema) e se Ho dimenticato di impostare una proprietà, il compilatore non dice nulla.

Cosa farai e perché? Sei a conoscenza di qualsiasi schema di luce (considera che dovrebbe essere usato ogni volta che un oggetto con le proprietà 7+ viene istanziato) per suggerire? Lo chiedo perché tendo a non gradire i grandi costruttori in cui non riesco a capire velocemente dove è la variabile che sto cercando, d'altra parte trovo che "imposta tutte le proprietà" sia vulnerabile alla mancanza di alcune proprietà .

Sentitevi liberi di argomento mie ipotesi in pro e contro in quanto sono solo pensieri miniera :)

Aggiornamento - una domanda che ho trovato che è legato a questo: Building big, immutable objects without using constructors having long parameter lists

risposta

20

Si potrebbe guardare il modello Builder sostenuto da Joshua Bloch e descritto in Java efficace. C'è una presentazione con i punti principali allo http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf; non c'è dubbio che potresti trovare un riferimento migliore.

Fondamentalmente, si dispone di un'altra classe, probabilmente una classe interna, che fornisce metodi denominati in base alle proprietà impostate e che restituiscono il generatore originale in modo da poter concatenare le chiamate. Rende un pezzo di codice abbastanza leggibile.

Ad esempio, supponiamo di avere un semplice Message con alcune proprietà. Il codice client costruire questo potrebbe utilizzare un costruttore per preparare un Message come segue:

Message message = new Message.Builder() 
    .sender(new User(...)) 
    .recipient(new User(...)) 
    .subject("Hello, world!") 
    .text(messageText) 
    .build(); 

Un frammento di Message.Builder potrebbe essere simile al seguente:

public class Builder { 

    private User sender = null; 
    // Other properties 

    public Builder sender(User sender) { 
     this.sender = sender; 
     return this; 
    } 
    // Methods for other properties 

    public Message build() { 
     Message message = new Message(); 
     message.setSender(sender); 
     // Set the other properties 
     return message; 
    } 

} 
+0

Grazie per il codice esplicativo –

+0

I builder sono davvero utili se si dispone di un oggetto complesso. Posso fortemente raccomandarlo. –

+0

e il libro! È davvero una lettura obbligata per i programmatori Java - è disponibile su O'Reilly Safari che è dove l'ho letto (abbiamo la sottoscrizione più piccola) –

26

ti sei perso il il più grande pro di avere un costruttore con un sacco di parametri: ti permette di creare tipi immutabili.

Il modo normale di creazione dei tipi immutabili senza enorme cattiveria costruttore è quello di avere un tipo di aiuto - un costruttore che mantiene i valori che vorrete nel vostro oggetto finale, poi costruisce l'oggetto immutabile quando sei pronto.

+0

Non è un costruttore la strategia migliore comunque? – Uri

+0

Inoltre, se lo stato dell'oggetto non può essere eseguito senza le proprietà impostate, forzare l'utente a impostarle passando attraverso il costruttore. –

+0

@Uri: il modello di builder è sopra l'IMO in alto se hai solo alcune proprietà. –

6

La recente ricerca accademica (CMU e Microsoft) sull'usabilità dell'API suggerisce che i costruttori predefiniti con i setter sarebbero la strada da percorrere in termini di usabilità. Questo è da "Implicazioni di usabilità di richiedere parametri a Costruttori Objects" di Jeff Stylos e Steven Clarke ed è stato presentato in occasione della Conferenza Internazionale sul Software Engineering:

Abstract: L'usabilità di API è sempre più importante al programmatore la produttività. Sulla base dell'esperienza con studi di usabilità di API specifiche, sono state esplorate le tecniche per studiare l'usabilità delle scelte progettuali comuni a molte API. È stato condotto uno studio comparativo per valutare in che modo i programmatori professionisti utilizzano le API con i parametri richiesti nei costruttori di oggetti rispetto ai costruttori "predefiniti" senza parametri. È stato ipotizzato che i parametri obbligatori avrebbero creato più API utilizzabili e autodocumentanti guidando i programmatori verso l'uso corretto degli oggetti e prevenendo gli errori.Tuttavia, nello studio, è emerso che, contrariamente alle aspettative, i programmatori preferivano fortemente e erano più efficaci con le API che non richiedevano parametri di costruzione. Il comportamento dei partecipanti è stato analizzato utilizzando la struttura delle dimensioni cognitive e rivelando che i parametri richiesti dal costruttore interferiscono con le strategie di apprendimento comuni, causando un impegno prematuro indesiderato.

0

Ci sono altri aspetti pure. Se vuoi essere in grado di certe cose con la tua classe in fase di progettazione piuttosto che in fase di runtime, ad esempio aggiungendo la tua classe come oggetto nella tavolozza degli oggetti (questo è Java usando Netbeans) devi fornire un costruttore senza argomenti in per essere in grado di farlo.

+0

Questa è una considerazione importante: gli strumenti ORM (ad esempio Hibernate anche se non sono sicuro che l'ultima versione sia ancora disponibile) tendono a richiedere setter accessibili e un costruttore predefinito. – hromanko

3

lo dici nel tuo post, ma penso che questo è un punto importante che merita più attenzione: a meno che tutti i parametri di input è un tipo diverso, il grosso problema con enormi costruttori è che è molto semplice trasposizione di una coppia di di variabili. Il compilatore è una rete di sicurezza inaffidabile: prenderà alcuni errori, ma quelli che scivoleranno saranno molto più difficili da identificare e mettere a punto. Soprattutto perché l'elenco di input per un enorme costruttore è piuttosto opaco a meno che tu non abbia l'API aperta in un'altra finestra.

I getter ei setter sono molto più facili da eseguire il debug, soprattutto se si istituiscono misure di protezione che generano un'eccezione di runtime se l'oggetto non è popolato correttamente. E io sono un grande fan di "easy to debug".

Prima di questo thread non avevo mai sentito parlare del pattern Builder che Rob menziona. Mai usato da solo (ovviamente), ma è dannatamente intrigante.

+0

Come si istituiscono le protezioni che generano un'eccezione di runtime se l'oggetto non è popolato correttamente? – mayu

0

Ci sono anche altre strategie qui. Prima di cercare di capire come gestire molti parametri, penso che sia importante rivedere il tuo design e vedere se la tua classe sta facendo troppo. Verifica se è possibile raggruppare alcuni dei parametri in una nuova classe e spostare alcuni comportamenti in quella classe.

2

Preferisco prendere gli argomenti del costruttore, per le ragioni di immutabilità di cui sopra.Se questo ti dà un costruttore che accetta molti argomenti (diciamo più di quattro o giù di lì), questo è un odore di codice per me: alcuni di questi argomenti dovrebbero essere raggruppati insieme nei loro tipi.

Per esempio, se avete qualcosa di simile:

class Contact 
{ 
    public Contact(string firstName, string lastName, string phoneNumber, 
     string street, string city, string state, int zipCode) { ... } 
} 

avrei refactoring a:

class Contact 
{ 
    public Contact(Person person, PhoneNumber number, Address address) { ... } 
} 

class Person 
{ 
    public Person(string firstName, string lastName) { ... } 
} 

class PhoneNumber 
{ 
    public PhoneNumber(string digits) { ... } 
} 

class Address 
{ 
    public Address(string street, string city, string state, int zipCode) { ... } 
} 

troppo grande classi sono un problema di progettazione molto comune in basi di codice OOP.

+0

come gestite con zipCode opzionale? –

+0

Sovraccarico Address's constructor. – munificent

0

Chi dice che non è possibile fare entrambe le cose? Direi che le proprietà obbligatorie entrano nel costruttore, quelle opzionali sono gestite con i setter. A proposito, chi dice che hai sempre bisogno di un setter per proprietà? Se due proprietà appartengono concettualmente, perché non metterle insieme?

Mi piace anche il pattern Builder, ma la regola più importante è: usa sempre il tuo cervello e trova il design che meglio si adatta al problema specifico. Non esiste una soluzione valida per tutti.

Problemi correlati