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.