I costruttori per le classi API devono mai essere pubblici oppure è sempre possibile utilizzare una fabbrica? [chiuso]

1

Sono sorpreso che questo non sia stato chiesto prima, o almeno non riesco a trovarlo da nessuna parte. So che questa è più una questione filosofica, ma c'è una ragione particolare non per usare una fabbrica (presumo che tutti conoscano i vantaggi del modello di fabbrica, quindi non entrerò in quella ) per l'istanziazione di classi API pubbliche? In altre parole, ci sono dei motivi per utilizzare un costruttore pubblico per tali classi oltre al fatto che è più veloce codificare che è forse meglio per le API veramente semplici e di piccole dimensioni?

    
posta rory.ap 26.06.2015 - 14:05
fonte

2 risposte

4

La semplicità.

Lo schema di fabbrica (non astratto, solo ordinario nella sua forma più semplice) è utile quando l'inizializzazione di una classe richiede una logica aziendale complessa. Mettere questa logica nel costruttore è spesso fuori questione, e avere la logica in un metodo statico all'interno della classe porta all'inquinamento di classe (e talvolta scarsa rilevabilità).

In un caso in cui la logica di inizializzazione è molto semplice, non è necessario creare classi aggiuntive e replicare questa logica. Ciò porterà a un numero maggiore di codice LOC, meno gestibile e più lavoro complessivo, con l'unico vantaggio dell'uniformazione (ovvero, ogni oggetto del codice base viene necessariamente creato attraverso un factory corrispondente).

Esempi:

  1. Un costruttore di classi Product accetta un argomento ProductId id e carica le informazioni aggiuntive dal database.

    Questo è un candidato perfetto per il modello di fabbrica. L'accesso al database non dovrebbe avvenire in un costruttore, il costruttore dovrebbe essere molto semplice, veloce e spesso non si prevede che generi eccezioni.

  2. Un costruttore di classi Price accetta gli argomenti int amount e Money unit .

    Questo è un esempio perfetto in cui non ha una fabbrica. Perchè vorresti? L'unica cosa che farà è passare gli argomenti al costruttore. Più complessità, nessun vantaggio.

  3. Un costruttore di classi Rebate accetta gli argomenti int amount e AmountUnit unit . A seconda della quantità e dell'unità, può esprimere una percentuale del prezzo totale, uno sconto assoluto o un "questo prodotto è gratuito" (che, per l'azienda, deve essere considerato in modo diverso dal rimborso del 100%).

    Qui puoi iniziare a scrivere codice all'interno del costruttore, e se il codice cresce, migralo in una fabbrica. A prima vista, non è chiaro se la complessità delle regole aziendali giustifica la creazione di una classe di fabbrica dedicata. Durante il ciclo di vita del codice sorgente Rebate , il team può passare più volte tra l'inizializzazione all'interno del costruttore e l'inizializzazione attraverso una classe factory.

risposta data 26.06.2015 - 14:12
fonte
0

Un esempio degno di attenzione riguarda le raccolte Java. La gerarchia di tipi al di sotto di Collection<T> ha alcune subinterfacce e tipi concreti. Ogni struttura di dati presenta vantaggi e svantaggi. Talvolta hanno proprietà aggiuntive al di sopra e al di là delle basi di una particolare struttura di dati come la sicurezza del thread o il mantenimento dell'ordine di inserimento in una struttura altrimenti confusa (ad esempio, alcune mappe e insiemi).

Per aiutare con questo, ci sono diverse fabbriche integrate nel JFC. La classe Collections può racchiudere una raccolta esistente in una che non è modificabile (la raccolta stessa è immutabile, gli elementi in essa contenuti possono o non possono essere). Può racchiudere una raccolta in un wrapper sincronizzato, offrendo una sicurezza di base per i thread (potrebbe non funzionare bene come le raccolte specializzate nel pacchetto di concorrenza). Può racchiudere un singolo elemento in una raccolta singleton (non nel modello singleton, solo in una raccolta con un elemento).

Questi sono tutti metodi di fabbrica: si chiama un metodo che restituisce un oggetto piuttosto che chiamare direttamente un costruttore. Sono utili perché consentono di adattare una raccolta che potrebbe essere creata al di fuori del proprio controllo (ad esempio in un framework o in una libreria) con vincoli aggiuntivi (ad es. Mutabilità o concorrenza) senza creare esplicitamente un nuovo oggetto.

Guava fa un ulteriore passo avanti con le sue utility di raccolta . Contiene molti altri metodi di fabbrica per creare nuove collezioni di vario tipo con varie proprietà. La costruzione può essere più concisa ed espressiva in questo modo. A livello concettuale non c'è altro da spiegare oltre la classeCollections di JFC%, ma noterò che Google ha compiuto un bel po 'di sforzi per costruire queste fabbriche perché aggiungono valore .

Questo è solo un esempio di dove le fabbriche possono essere utili, ma dovrebbero sempre essere usate?

Ci sono due ragioni principali per l'utilizzo di una fabbrica:

  • La costruzione è complessa. I costruttori dovrebbero essere semplici: hanno bisogno di dati o elaborazione aggiuntivi? Ad esempio, il caricamento dei dati da un file o da un database non dovrebbe essere eseguito in un costruttore, ma potrebbe essere necessario per creare un oggetto. Ha più senso inserire quell'elaborazione extra in un metodo factory.

  • L'implementazione deve variare a prescindere da dove vengono creati gli oggetti. Potresti voler utilizzare un'implementazione diversa in un momento futuro? Potrebbe essere variabile attraverso un'architettura di plugin? Potresti inserire una simulazione per testare?

Molte classi API non superano questi test. Ad esempio, una stringa avrà sempre la stessa implementazione e non richiede molta elaborazione aggiuntiva. L'API di base della maggior parte delle lingue / runtime deve essere abbastanza semplice per due motivi:

  • Sta risolvendo semplici problemi, ad es. "rappresenta una sequenza di caratteri in una stringa."

  • Deve essere applicabile a una vasta gamma di problemi e altamente riutilizzabile, che è in contrasto con una classe altamente specializzata.

Questa semplicità è in contrasto con i requisiti per l'utilizzo di una fabbrica. Quando un tipo è abbastanza semplice che un costruttore no-arg o one-arg è tutto ciò che è sempre necessario, e l'implementazione sarà sempre la stessa, non ha senso usare una fabbrica.

Nota che sto parlando dell'API core qui (stringhe, raccolte, flussi), non di cose come database, GUI o altre librerie più complesse.

    
risposta data 26.06.2015 - 14:45
fonte

Leggi altre domande sui tag