2009-03-30 12 views
21

Ho cercato un buon esempio di un modello di Builder (in C#), ma non riesce a trovare uno o perché non capisco il modello Builder o sto cercando di fare qualcosa che fosse mai inteso. Per esempio, se ho una macchina astratta e metodi di costruzione astratti per creare parti di automobili, dovrei essere in grado di inviare tutte le 30 delle mie scelte al regista, farlo costruire i pezzi che mi servono, quindi costruire la mia automobile. Indipendentemente dal tipo di auto, camion, semi, ecc. Prodotto, dovrei essere in grado di "guidarlo" esattamente nello stesso modo.Design: Builder

Il primo problema è la maggior parte degli esempi di valori di proprietà del codice rigido nelle parti in calcestruzzo, che penso che dovrebbero provenire da un database. Ho pensato che l'idea fosse di inviare le mie scelte al direttore (da una fonte di dati) e fare in modo che il costruttore creasse un prodotto personalizzato basato sui miei dati.

Il secondo problema è che voglio che i metodi builder creino effettivamente le parti, quindi le assegniamo al prodotto, non passiamo stringhe ma parti di prodotto fortemente tipizzate.

Ad esempio, desidero creare un modulo al volo disponendo di un modulo di compilazione per i campi del modulo, inclusa un'etichetta, una sezione di input, la convalida, ecc. In questo modo posso leggere l'oggetto dal mio ORM, controllare fuori i metadati dell'oggetto, passare questo al mio Builder e aggiungere il risultato del controllo utente appena creato al mio modulo web.

Tuttavia, ogni esempio di Builder che trovo ha solo dati hard coded invece di passare le scelte dal codice principale al Builder e dare il via a un prodotto personalizzato. Tutto sembra essere una grande affermazione di un caso statico. Ad esempio, se ho tre parametri con 10 scelte ciascuno, non voglio creare 30 metodi Concrete Builder, voglio creare solo quanto basta per produrre le proprietà richieste dal mio prodotto, che possono essere solo tre.

Sono tentato di avere il direttore solo nel codice principale. Ci dovrebbe essere un modo per determinare automaticamente quale metodo di builder concreto chiamare simile al polymorphism e agli overload dei metodi (sebbene questo sia un pessimo esempio) invece di usare un'istruzione case all'interno del pattern. (Ogni volta che ho bisogno di aggiungere un nuovo tipo di prodotto, ho bisogno di modificare il Director esistente, che è male).

+0

forse, ciò che manca nel modello di builder, è che gli oggetti non vengono distrutti alla fine, quindi suggerisco di aggiungerlo più tardi se non hai inteso il modello ... – Tobias

+0

Non proprio quello che vuoi, ma controlla questi articoli:
[la descrizione del modello] (http://sourcemaking.com/design_patterns/builder)
[esempio di implementazione C#] (http://sourcemaking.com/design_patterns/builder/c%2523)
Spero che questo aiuta. – 0x49D1

risposta

10

Mi riferisco all'esempio C# nell'articolo di Wikipedia here.

Il primo problema è la maggior parte degli esempi di valori di proprietà del codice rigido nelle parti in calcestruzzo, che penso che dovrebbero provenire da un database. Ho pensato che l'idea fosse di inviare le mie scelte al direttore (da una fonte di dati) e fare in modo che il costruttore creasse un prodotto personalizzato basato sui miei dati.

In questo caso si dovrebbe implementare la classe PizzaBuilder che sa come recuperare i dati da un database. Puoi farlo in diversi modi.

Uno sarebbe fare un HawaiianPizzaBuilder. Quando la classe si inizializza, interroga il database per una pizza hawaiana e recupera la riga. Quindi, quando vengono chiamati i vari metodi di Build (x), esso imposterà le proprietà nel campo corrispondente della riga del database recuperato.

Un altro sarebbe solo fare un PizzaDatabaseBuilder e assicurarsi che quando si inizializza la classe si passa l'ID della riga necessaria per quel tipo di pizza. Per esempio, invece di

waiter.PizzaBuilder = new HawaiianPizzaBuilder(); 

Si utilizza

waiter.PizzaBuilder = new PizzaDatabaseBuilder("Hawaiian"); 

Secondo problema è che voglio i metodi Builder per creare effettivamente le parti poi assegnarli al prodotto, non passa le stringhe ma reale fortemente tipizzato prodotto parti.

Non dovrebbe essere un problema. Quello di cui hai bisogno è un altro tipo di modello Factory/Builder per inizializzare i campi della Pizza. Per esempio

invece di

public override void BuildDough() { pizza.Dough = "pan baked"; } 

si dovrebbe fare qualcosa di simile

public override void BuildDough() { pizza.Dough = new DoughBuilder("pan baked"); } 

o

public override void BuildDough() { pizza.Dough = new PanBakedDoughBuilder(); } 

DoughBuilder può andare in un'altra tabella nel database di compilare correttamente un PizzaDough Classe.

+0

Buona risposta. Se usiamo classi di produzione dichiarate staticamente, non avremmo bisogno del nuovo operatore. Anche il richiamo del costruttore di Tobiask è sorprendente, come jQuery. La risposta è sia dove non avresti bisogno di un regista è quello che sto prendendo da tutto questo. Il trucco sarà codificarlo per davvero. Grazie mille. –

+0

Più capisci questa risposta, più ti rendi conto di quanto RS Conley conosca. :) +100 se potessi. –

0

Direi che non è possibile evitare nessuno di questi: avere pochi sovraccarichi per le parti e avere un'istruzione caso/se da qualche parte in cima allo stack. Anche dover modificare il codice quando si aggiunge una nuova classe potrebbe essere la tua unica opzione.

Detto questo, puoi ottenere aiuto con altri schemi, ovvero Factory che potrebbe aiutarti nel processo di costruzione. Anche l'uso sensibile del polimorfismo (ad esempio tutte le parti ereditate da alcuni tipi che siano di classe o di interfaccia) può ridurre la quantità di casi/casi e sovraccarichi.

Spero che questo aiuti.

19

Per lo più il richiamo di un builder si presenta così:

Car car = new CarBuilder().withDoors(4).withColor("red").withABS(true).build(); 
+2

Questo non è in realtà il pattern Builder come descritto da Design Patterns. Il modello è progettato per creare diverse rappresentazioni della stessa fonte. Ad esempio, un compilatore che utilizza un parser ma ha backend diversi per x86, x64 e Java Byte Code. –

+4

Potrebbe non essere esattamente come descritto dai Design Pattern ma garantisce che l'oggetto creato abbia tutte le proprietà impostate correttamente. Puoi anche fare in modo che l'object builder usi un'interfaccia fluente ... ma questo è per un'altra domanda – Kane

10

ci ho mai pensato in questo modo, ma LINQ (il modello, non la sintassi) è in realtà un costruttore, giusto?

È un'interfaccia fluente che crea una query e può creare query in rappresentazioni diverse (SQL, query di oggetti in memoria, query di servizi Web, anche Bart de Smet ha scritto un'implementazione di Linq-to-Excel).

+0

Sì, assolutamente. –