2009-03-04 11 views
12

Tengo dificultades para entender lo que mi clase de fábrica debería hacer en mi proyecto DDD. Sí, se debe usar una fábrica para crear objetos, pero qué debería estar haciendo exactamente. Considere la siguiente clase de fábrica:¿Qué métodos deberían ir en mi clase de fábrica DDD?

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; 
     } 
    } 

¿Debo hacer una llamada directa al depósito desde la fábrica?

¿Cómo debo gestionar la creación de objetos cuando recupero datos de una base de datos?

¿Qué necesito para completar esta clase? ¿Qué otros métodos debo tener?

¿Debo utilizar esta clase para crear el objeto del producto desde el dominio y el depósito desde la derecha?

Por favor ayuda!

+1

No ponga la lógica repositorio en su fábrica. – mbillard

Respuesta

0

En el ejemplo anterior, no estoy muy claro sobre la distinción entre su fábrica y el repositorio. Me pregunto si no debería simplemente agregar CreateProduct como un método al repositorio, y usar DI para insertar el repositorio en el código que lo necesita. Si la fábrica no es haciendo nada, etc ...

O si lo que desea es que le permite actuar como un repositorio registrado a nivel mundial, tal vez algo como:

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

(en mi mente parece más clara para separar el "conjunto" en este caso, pero usted no tiene que estar de acuerdo)

y tienen las personas que llaman usan var product = YourFactory.Default.CreateProduct(); etc

1

personalmente usaría la fábrica en dos circunstancias:

1) Algo en otro lugar determina qué tipo de objetos devuelve esta fábrica (es decir. puede devolver objetos dependiendo de las circunstancias. Por ejemplo, devolver un objeto stub cuando estoy probando, devolver una implementación real cuando no lo estoy (esto es obviamente más un problema de Inversión de Control/Inyección de Dependencia - pero si aún no quiere agregar contenedores a su proyecto)).

2) Tengo objetos bastante complejos que tienen contenedores, dependencias, otras relaciones, etc. y deben construirse con cuidado para evitar crear referencias nulas o sin sentido. Por ejemplo, si tengo un objeto Schedule, puedo necesitar establecer algunos campos de inicio, fecha de finalización; si la lógica para recuperarla, descubrir esta fecha es lo suficientemente compleja, es posible que no desee que la clase llamante lo sepa y llamar al método predeterminado de fábrica que creó el objeto de programación.

Espero que esto ayude.

2

Lo que debe ir en el método Crear de tu fábrica es lo que sea necesario para poner un nuevo objeto de marca en un estado VÁLIDO.

Ahora, para algunos objetos que significa que no se hacer otra cosa que esto:

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

Sin embargo, es posible que tenga reglas de negocio, los valores predeterminados u otros requisitos que desea cumplir cuando un objeto está creado. En ese caso, pondrías esa lógica en ese método.

Y eso es parte del beneficio de la fábrica.Ahora tiene uno y solo un lugar donde reside esa lógica especial, y solo un lugar donde se crea un nuevo objeto.

11

¿Debería estar haciendo una llamada directa a el repositorio desde el interior de la fábrica ?

No, no utilice una fábrica cuando recupere cosas, use una fábrica solo cuando la esté creando por primera vez.

¿Cómo debo gestionar la creación de objetos al recuperar datos de una base de datos?

Transfiere esos datos a la fábrica, si es necesario para la creación inicial del objeto.

¿Qué necesito para hacer esta clase completa, lo que otros métodos debe tener i?

Muchas fábricas ni siquiera son clases individuales, solo son métodos que proporcionan la creación de objetos. Podría doblar el método de fábrica en otra clase, si tuviera la sensación de que simplemente llamaría a un constructor sin parámetros.

¿Debería utilizar esta clase para crear el objeto Producto del dominio y repositorio de derecha?

El repositorio es para obtener (en cierto sentido, crear) objetos existentes, la fábrica es la primera vez que crea un objeto.

Inicialmente, muchas fábricas no harán mucho excepto llamar a un constructor. Pero una vez que comienza a refactorizar y/o crear jerarquías de objetos más grandes, las fábricas se vuelven más relevantes.

Explicación y Ejemplo:

Por ejemplo, en el proyecto que estoy trabajando en la I tienen una clase base procesador de excel y muchas subclases de aplicación de esta clase base. Utilizo la fábrica para obtener la correcta, y luego invoco métodos, ignorante de qué subclase se devolvió. (Nota: Cambié algunos nombres de variables y destripé/modifiqué una gran cantidad de código)

Clase base del procesador:

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

Una de las subclases Procesador:

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

fábrica:

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

Atención, hay dos razones para instanciar un nuevo objeto: Creación de y rehidratación desde la base de datos.

El primer caso es manejado por la fábrica. Puede proporcionar varios métodos para crear un objeto en la fábrica. Los métodos de fábrica deben devolver objetos válidos, por lo que puede pasar parámetros a estos métodos para proporcionar la información requerida.

El método de fábrica también puede elegir el tipo real para crear instancias en función de los parámetros.

No debe mezclar esto con la rehidratación de la base de datos. Este tipo de creación de instancias debería tomar valores del datarow y crear una instancia del objeto con él. Generalmente llamo a esto creador de datos en lugar de fábrica.

La principal diferencia es que la fábrica creará una instancia de un objeto con una nueva identidad, mientras que el creador de datos creará una instancia de un objeto con una identidad ya existente.

+3

La fábrica está generalmente en el dominio mientras el generador de datos está en la infraestructura de persistencia. – thinkbeforecoding

0

@ThinkBeforeCoding: en el ejemplo de @ m4bwav, la fábrica obtiene una identificación válida de un método de ayuda, pero no está creando un nuevo registro en una capa de persistencia en ningún lado. Sin embargo, si estoy usando una columna de identidad autogenerada como mis identidades, parece que una fábrica tendría que llamar al repositorio para hacer la creación inicial del objeto. ¿Puedes comentar sobre qué método es "correcto"?

0

En el constructor puede tener cualquier lógica que necesita para inForce los invariantes en sus ENTIDADES, un pequeño ejemplo utilizando Java como lenguaje de desarrollo ...

que tienen una entidad de usuario que tiene un nombre de usuario, una contraseña y un correo electrónico, todos los atributos requeridos por lo que tengo:

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 
} 

y luego tengo la 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; 
} 
}; 

y se puede utilizar el constructor como esto :

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 
} 

El único propósito de la fábrica es crear instancias válidas de objetos. Para no duplicar el código de creación e hidratación, puede tener sus repositorios para consultar un conjunto de filas de la base de datos y delegar la creación del objeto a un constructor que pase los datos del conjunto de filas.

Esperanza esto ayuda

Gracias Pablo

Cuestiones relacionadas