2009-03-04 38 views
12

Sto facendo fatica a capire cosa dovrebbe fare la mia lezione di fabbrica nel mio progetto DDD. Sì, una fabbrica dovrebbe essere usata per creare oggetti, ma cosa dovrebbe fare esattamente. Considerare la seguente classe di fabbrica:Quali metodi dovrebbero essere usati nella mia classe DDD factory?

public class ProductFactory 
    { 
     private static IProductRepository _repository; 

     public static Product CreateProduct() 
     { 
      return new Product(); 
     } 

     public static Product CreateProduct() 
     { 
      //What else would go here? 
     } 

     public static Product GetProductById(int productId) 
     { 
      //Should i be making a direct call to the respoitory from here? 
      Greener.Domain.Product.Product p = _repository.GetProductById(productId); 
      return p; 
     } 
    } 

Devo effettuare una chiamata diretta al repository dalla fabbrica?

Come devo gestire la creazione dell'oggetto durante il recupero dei dati da un database?

Cosa devo fare per completare questa classe, quali altri metodi dovrei avere?

Devo usare questa classe per creare l'oggetto Product dal dominio e dal repository di destra?

Si prega di aiuto!

+1

Non mettere la logica repository nella tua fabbrica. – mbillard

risposta

0

Nell'esempio sopra riportato, sono un po 'incerto sulla distinzione tra fabbrica e repository. Mi chiedo se non dovresti semplicemente aggiungere CreateProduct come metodo al repository e usare DI per spingere il repository nel codice che ne ha bisogno? Se la fabbrica non è facendo nulla, ecc ...

O se volete semplicemente di agire come un repository registrati a livello globale, forse qualcosa di simile:

public static IFooRepository Default {get;private set;} 
public static void SetRepository(IFooRepository repository) { 
    Default = repository; 
} 

(nella mia mente sembra più chiaro per separare il "set" in questo caso, ma voi non essere d'accordo)

e hanno i chiamanti utilizzano var product = YourFactory.Default.CreateProduct(); ecc

1

io personalmente avrei usato la fabbrica in un paio di circostanze:

1) Qualcosa altrove governa il tipo di oggetti restituiti da questa fabbrica (es. può restituire oggetti a seconda delle circostanze. Ad esempio, restituisco un oggetto stub quando eseguo il test, restituisco un'implementazione effettiva quando non lo sono (si tratta ovviamente più del problema di Inversion of Control/Dependency Injection - ma se non vuoi ancora aggiungere container al tuo progetto)).

2) Ho oggetti piuttosto complessi che hanno contenitori, dipendenze, altre relazioni ecc. E devono essere costruiti con cura per evitare di creare riferimenti nulli o privi di significato. Ad esempio, se ho un oggetto Schedule, potrei aver bisogno di alcuni campi di data di inizio, fine impostati - se la logica per il recupero, capire che questa data è abbastanza complessa, potrei non volere che la classe chiamante ne sappia e basta chiamare il metodo predefinito di fabbrica che ha creato l'oggetto pianificazione.

Spero che questo aiuti.

2

Quello che dovrebbe andare nel metodo di creazione della vostra fabbrica è tutto ciò che è necessario per mettere un nuovo oggetto di marca in uno stato VALIDO.

Ora, per alcuni oggetti che significa che non dovrete fare altro che questo:

public Product Create() 
{ 
    return new Product(); 
} 

Tuttavia, è possibile che le regole di business, le impostazioni predefinite o altri requisiti che si desidera applicare quando un oggetto è creato. In tal caso, metteresti quella logica in quel metodo.

E questo fa parte del vantaggio della fabbrica.Ora disponi di un solo e unico luogo in cui risiede quella logica speciale e solo un punto in cui viene creato un nuovo oggetto.

11

dovrei essere fare una chiamata diretta al repository all'interno della fabbrica ?

No, non utilizzare una fabbrica quando si recuperano materiali, utilizzare una fabbrica solo quando la si sta creando per la prima volta.

Come devo gestire la creazione dell'oggetto durante il recupero dei dati da un database?

Inserire i dati in fabbrica, se necessario per la creazione iniziale dell'oggetto.

Di cosa ho bisogno per rendere questa classe completo, quali altri metodi dovrei avere?

Molte fabbriche non sono nemmeno singole classi, sono solo metodi che forniscono la creazione di oggetti. Si potrebbe passare il metodo factory in un'altra classe, se si sentisse che avrebbe chiamato un costruttore senza parametri.

Dovrei usare questa classe per creare l'oggetto prodotto dal dominio e repository da destra?

Il repository serve per ottenere (in un certo senso creare) oggetti esistenti, la fabbrica è la prima volta che si crea un oggetto.

Inizialmente molte fabbriche non faranno molto se non chiamare un costruttore. Ma una volta avviato il refactoring e/o la creazione di gerarchie di oggetti più grandi, le fabbriche diventano più rilevanti.

Spiegazione e Esempio:

Ad esempio, nel progetto sto lavorando Ho una classe base processore Excel e molte sottoclassi d'attuazione classe di base. Io uso la fabbrica per ottenere quella corretta e quindi chiamo metodi, ignorando la sottoclasse restituita. (Nota: ho cambiato alcuni nomi di variabili e ho cancellato/alterato un sacco di codice)

Classe di base del processore:

public abstract class ExcelProcessor 
{ 
     public abstract Result Process(string ExcelFile); 
} 

una delle sottoclassi processore:

public class CompanyAExcelProcessor : ExcelProcessor 
{ 
    public override Result Process(string ExcelFile) 
    { 
     //cool stuff 
    } 
} 

fabbrica:

public static ExcelProcessor CreateExcelProcessor(int CompanyId, int CurrentUserId) 
{ 
     CompanyEnum company = GetCompanyEnum(CompanyId); 
     switch (company) 
     { 
      case CompanyEnum.CompanyA: 
       return new CompanyAExcelProcessor(); 
      case CompanyEnum.CompanyB: 
       return new CompanyBExcelProcessor(); 
      case CompanyEnum.CompanyC: 
       return new CompanyCExcelProcessor(CurrentUserId); 
      //etc... 
     } 
} 

Uso:

ExcelProcessor processor = CreateExcelProcessor(12, 34); 
processor.Process(); 
6

Attenzione, ci sono due ragioni per un'istanza di un nuovo oggetto: Creazione e reidratante dal database.

Il primo caso è gestito dalla fabbrica. È possibile fornire diversi metodi per creare un oggetto in fabbrica. I metodi di fabbrica devono restituire oggetti validi, quindi è possibile passare i parametri a questi metodi per fornire le informazioni richieste.

Il metodo di fabbrica può anche scegliere il tipo effettivo da istanziare in base ai parametri.

Non si deve mescolare questo con reidratazione dal database. Questo tipo di istanziazione dovrebbe prendere i valori dal datarow e istanziare l'oggetto con esso. Solitamente lo chiamo costruttore di dati anziché .

La differenza principale è che la fabbrica istanzia un oggetto con una nuova identità mentre il generatore di dati crea un'istanza di un oggetto con un'identità già esistente.

+3

Lo stabilimento è solitamente nel dominio mentre il generatore di dati si trova nell'infrastruttura di persistenza. – thinkbeforecoding

0

@ThinkBeforeCoding - nell'esempio di @ m4bwav, la factory sta ottenendo un ID valido da un metodo helper, ma non sta creando un nuovo record in un livello di persistenza da nessuna parte. Se, tuttavia, sto usando una colonna Identity generata automaticamente dal database come identità, sembra che una factory debba chiamare nel repository per fare la creazione dell'oggetto iniziale. Puoi commentare quale metodo è "corretto"?

0

Nel generatore si può avere qualsiasi logica è necessario rinforzare le invarianti sulle entités, un piccolo esempio utilizzando Java come linguaggio di sviluppo ...

Ho un entità User che ha un nome utente, una password e una e-mail, tutti gli attributi richiesti in modo da avere:

public class User { 

private String username; 
private String password; 
private String email: 

/** 
* @throws IllegalArgumentException if the username is null, the password is null or the 
* email is null. 
*/ 
public User(final String theUsername, final String thePassword, final String theEmail) { 
Validate.notNull(theUsername); 
Validate.notNull(thePassword); 
Validate.notNull(theEmail); 

this.username = theUsername; 
this.password = thePassword; 
this.email = theEmail; 
} 

// Getters/Setters/equal/hashCode/toString 
} 

e poi ho l'UserBuilder:

public class UserBuilder { 
private String username; 
private String password; 
private String email; 

public UserBuilder withUsername(final String theUsername) { 
Validate.notNull(theUsername); 

this.username = theUsername; 

return this; 
} 

public UserBuilder withPassword(final String thePassword) { 
Validate.notNull(thePassword); 

this.password = thePassword; 

return this; 
} 

public UserBuilder withEmail(final String theEmail) { 
Validate.notNull(theEmail); 

this.email = theEmail; 

return this; 
} 

public User build() { 
User user = new User(this.username, this.password, this.email); 

return user; 
} 
}; 

ed è possibile utilizzare il costruttore come questo :

UserBuilder builder = new UserBuilder(); 

try { 
User user = builder.withUsername("pmviva").withPassword("My Nifty Password").withEmail("[email protected]").build(); 
} catch (IllegalArgument exception) { 
    // Tried to create the user with invalid arguments 
} 

L'unico scopo della fabbrica è creare istanze valide di oggetti. Per non duplicare il codice di creazione e di idratazione, è possibile fare in modo che i repository interrogino un set di righe dal database e delegano la creazione dell'oggetto a un builder che passa i dati del set di righe.

Spero che questo aiuti

Grazie Pablo

Problemi correlati