Costruire una classe che contiene classi costruite

3

Ho alcune classi che ho creato che sono immutabili e seguono il modello di builder. Sto creando una classe composita che includerà quelle classi come campi. Il costruttore di quella classe composita deve chiamare i sub-builder e quindi costruirli nel metodo build() del builder esterno, oppure il builder composito deve avere metodi che accettano istanze già costruite delle classi contenute, o devo consentire entrambe le opzioni ?

    
posta TBridges42 10.07.2015 - 20:08
fonte

2 risposte

4

Prenderò per scontato che le tue classi siano chiamate Composite, Foo, Bar e Baz.

L'opzione più semplice è quella di consentire a CompositeBuilder di prendere Foos / Bar / Baz pre-costruiti, in modo da ottenere nuovi CompositeBuilder (). setFoo (...). setBar (...). setBaz (...). (). Il grande vantaggio qui è che l'API della tua classe Composite è estremamente semplice, sia per te che per i tuoi utenti. KISS e YAGNI si applicano qui. Inoltre, hai ancora l'opzione di sottoclasse di Foo / Bar / Baz, e questo potrebbe rendere più facile cambiare Foo / Bar / Baz da soli, dal momento che Composite non deve sapere molto su di loro.

L'alternativa di avere CompositeBuilder fornisce la propria interfaccia ha altri potenziali vantaggi, presupponendo che tu fornisca un'interfaccia molto più piccola e più stretta di quella che ottieni "gratuitamente" dai tre sottobbuilder. Questo può potenzialmente rendere molto più facile il lavoro con Composite, e apre la possibilità di cambiare un giorno Composite per usare Oof / Rab / Zab invece di Foo / Bar / Baz senza influenzare il codice client, nel caso in cui la sottoclasse non sia sufficiente.

Eviterei di fornire entrambi, a meno che tu non sia molto sicuro di avere molti utenti che desiderano un'interfaccia semplificata e molti altri utenti che ne hanno bisogno potenza di un FooBuilder grezzo. Cercare di fare troppe cose contemporaneamente rischia sempre di non farle bene (e rendere difficile per chiunque capire come dovrebbero usare Composite).

Quale scegliere dovrebbe dipendere da molti fattori che non hai descritto. Quanto sono complicati i tre subbuilder? Di quanta personalizzazione ha bisogno un composito? Gli utenti di CompositeBuilder avranno già familiarità con Foo / Bar / BazBuilders? Disprezzano le attuali interfacce Foo / Bar / BazBuilder? Esistono "consumatori" e "produttori" separati di questi oggetti, o sono solitamente utilizzati nello stesso luogo in cui sono costruiti? Avrebbe mai senso cambiare le classi in cui è implementato Composite? E così via e così via.

    
risposta data 10.07.2015 - 20:54
fonte
4

Tendo a preferire un costruttore per ogni oggetto che accetta oggetti secondari completamente costruiti.

La ragione principale è che questo percorso fornisce semplicità di implementazione, senza perdita di flessibilità di espressione. Inoltre, lo trovo più leggibile.

Confronta due esempi completamente faziosi:

CompositeClass.builder()
              .withArgument(some_arg)

              .withSubclass1Argument1(some_arg)
              .withSubclass1Argument2(some_arg)

              .withSubclass2Argument1(some_arg)
              .withSubclass2Argument2(some_arg)
              .build();

vs

CompositeClass.builder()
              .withArgument(some_arg)
              .withSubclass1(Subclass1.builder()
                                      .withArgument1(some_arg)
                                      .withArgument2(some_arg)
                                      .build())
              .withSubclass2(Subclass2.builder()
                                      .withArgument1(some_arg)
                                      .withArgument2(some_arg)
                                      .build())
              .build()

Si tratta di preferenze personali, ma trovo il secondo più facile da leggere e utilizzare.

    
risposta data 10.07.2015 - 21:06
fonte

Leggi altre domande sui tag