Costruttore con tutte le proprietà di classe o costruttore predefinito con setter?

StackOverflow https://stackoverflow.com/questions/830657

  •  06-07-2019
  •  | 
  •  

Domanda

Di seguito sono riportati i due approcci:

  • costruttore con tutte le proprietà della classe

Pro: devo inserire un numero esatto di tipi di parametri, quindi se faccio un errore il compilatore mi avverte (a proposito, c'è un modo per prevenire il problema di aver commutato erroneamente due numeri interi nell'elenco dei parametri? )

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

  • setter e il costruttore vuoto predefinito

Pro: posso vedere chiaramente cosa sto impostando, quindi se sto facendo qualcosa di sbagliato posso individuarlo non appena lo sto digitando (non posso fare l'errore precedente di cambiare due variabili del stesso tipo)

Contro: l'istanza di un oggetto con molte proprietà potrebbe prendere diverse righe (non so se si tratta davvero di un contro) e se dimentico di impostare una proprietà il compilatore non dice nulla.

Cosa farai e perché? Conosci qualche modello di luce (considera che dovrebbe essere usato ogni volta che un oggetto con più di 7 proprietà viene istanziato) per suggerire? Lo sto chiedendo perché tendo a non apprezzare i grandi costruttori in cui non riesco a capire velocemente dov'è la variabile che sto cercando, d'altra parte trovo il " set all properties " vulnerabile alla mancanza di alcune proprietà.

Sentiti libero di contestare le mie assunzioni in pro e contro in quanto sono solo i miei pensieri :)

Aggiornamento - ho trovato una domanda che è correlata a questo: Creazione di oggetti grandi e immutabili senza l'uso di costruttori con lunghi elenchi di parametri

È stato utile?

Soluzione

Potresti guardare il modello Builder sostenuto da Joshua Bloch e descritto in Java efficace . C'è una presentazione con i punti principali su http: //developers.sun .com / apprendimento / javaoneonline / 2007 / pdf / TS-2689.pdf ; senza dubbio potresti trovare un riferimento migliore.

Fondamentalmente, hai un'altra classe, probabilmente una classe interna, che fornisce metodi che prendono il nome dalle proprietà impostate e che restituiscono il builder originale in modo da poter concatenare le chiamate. Rende abbastanza un pezzo leggibile di codice.

Ad esempio, supponiamo che io abbia un semplice Message con alcune proprietà. Il codice client che costruisce questo potrebbe usare un builder 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 apparire 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;
    }

}

Altri suggerimenti

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

Il modo normale di creare tipi immutabili senza l'enorme cattiveria del costruttore è avere un tipo di supporto - un costruttore che mantenga i valori desiderati nel tuo oggetto finale, quindi crea l'oggetto immutabile quando sei pronto.

Recenti ricerche accademiche (CMU e Microsoft) sull'usabilità dell'API suggeriscono che i costruttori predefiniti con setter sarebbero la strada da percorrere in termini di usabilità. Ciò deriva da "Implicazioni sull'usabilità dei parametri obbligatori nei costruttori di oggetti". di Jeff Stylos e Steven Clarke ed è stato presentato alla Conferenza internazionale sull'ingegneria del software:

Abstract : L'usabilità delle API è sempre più importante per la produttività del programmatore. Sulla base dell'esperienza con gli studi sull'usabilità di API specifiche, sono state esplorate tecniche per studiare l'usabilità delle scelte di progettazione 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 a "default" senza parametri; costruttori. È stato ipotizzato che i parametri richiesti avrebbero creato API più utilizzabili e autocompattanti guidando i programmatori verso l'uso corretto degli oggetti e prevenendo gli errori. Tuttavia, nello studio, è stato scoperto che, contrariamente alle aspettative, i programmatori preferivano fortemente ed erano più efficaci con le API che non richiedevano parametri del costruttore. Il comportamento dei partecipanti è stato analizzato utilizzando il quadro delle dimensioni cognitive e rivelando che i parametri costruttivi richiesti interferiscono con le strategie di apprendimento comuni, causando un impegno prematuro indesiderato.

Lo dici nel tuo post, ma penso che questo sia un punto importante che merita maggiore attenzione: a meno che ogni parametro di input non sia un tipo diverso, il grosso problema con costruttori enormi è che è molto facile per trasporre un paio di variabili. Il compilatore è una rete di sicurezza inaffidabile: colpirà alcuni errori, ma quelli che sfuggiranno saranno molto più difficili da identificare e eseguire il debug. 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.

Il debug e i setter sono molto più facili da eseguire il debug, soprattutto se si istituiscono protezioni che generano un'eccezione di runtime se l'oggetto non viene popolato correttamente. E sono un grande fan di " facile da eseguire il debug "

Prima di questo thread non avevo mai sentito parlare del modello Builder menzionato da Rob. Non l'ho mai usato da solo (ovviamente), ma è dannatamente intrigante.

Preferisco prendere argomenti costruttivi, per i motivi di immutabilità sopra menzionati. 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 quegli argomenti dovrebbero essere raggruppati insieme nei loro tipi.

Ad esempio, se hai qualcosa del genere:

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

Lo rifatterò in:

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) { ... }
}

Le classi troppo grandi sono un problema di progettazione molto comune nelle basi di codice OOP.

Ci sono anche altri aspetti. Se vuoi essere in grado di determinate cose con la tua classe in fase di progettazione piuttosto che solo 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 poterlo fare.

Ci sono anche altre strategie qui. Prima di provare a capire come gestire molti parametri, penso che sia importante visitare nuovamente il tuo progetto e vedere se la tua classe sta facendo troppo. Verifica se riesci a raggruppare alcuni parametri in una nuova classe e spostare alcuni comportamenti in quella classe.

  

setter e costruttore vuoto predefinito

JRL ha toccato obliquamente su di esso , ma un motivo per considerare l'uso dei setter è che l'oggetto sia conforme alla specifica JavaBean . Questo rende le istanze suscettibili di editing tramite strumenti di introspezione e persistenza utilizzando alcune tecniche di serializzazione .

Chi dice che non puoi fare entrambe le cose? Direi che le proprietà obbligatorie vanno nel costruttore, quelle opzionali vengono gestite con setter. A proposito, chi dice che hai sempre bisogno di un setter per proprietà? Se due proprietà si uniscono concettualmente, perché non impostarle insieme?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top