2010-12-17 22 views
9

Tengo un método en un repositorio con una lógica de negocio muy compleja. Acabo de leer que no debería haber lógica de negocios en un repositorio.Lógica comercial compleja en el repositorio

Eliminar la lógica de negocio de este método me obligará a distribuir la lógica entre otros dos repositorios (porque involucra a otras dos entidades).

Entonces mi pregunta es: ¿qué patrón debería usar para implementar esta compleja lógica? Necesitará consumir estos tres repositorios, pero no puedo ubicarlo en un controlador porque necesito reutilizarlo. Gracias por tu ayuda.

Respuesta

9

La lógica comercial compleja por lo general entra en una capa de servicio. Un servicio puede depender de uno o más repositorios para realizar operaciones CRUD en sus modelos. Por lo tanto, una única operación de servicio que represente una operación comercial puede depender de múltiples operaciones simples. Entonces podría reutilizar esta capa de servicio en sus controladores y otras aplicaciones.

Obviamente, su servicio no debe depender de implementaciones de repositorio específicas. Para proporcionar un acoplamiento más débil entre la capa de servicio y los repositorios, podría usar interfaces. Aquí hay un ejemplo:

public interface IProductsRepository { } 
public interface IOrdersRepository { } 
... 

public interface ISomeService 
{ 
    void SomeBusinessOperation(); 
} 

public class SomeServiceImpl: ISomeService 
{ 
    private readonly IProductsRepository _productsRepository; 
    private readonly IOrdersRepository _ordersRepository; 

    public SomeServiceImpl(
     IProductsRepository productsRepository, 
     IOrdersRepository ordersRepository 
    ) 
    { 
     _productsRepository = productsRepository; 
     _ordersRepository = ordersRepository; 
    } 

    public void SomeBusinessOperation() 
    { 
     // TODO: use the repositories to implement the business operation 
    } 
} 

Ahora todo lo que queda es configurar su infraestructura DI para inyectar este servicio específico en su controlador.

public class FooController : Controller 
{ 
    private readonly ISomeService _service; 
    public FooController(ISomeService service) 
    { 
     _service = service; 
    } 

    public ActionResult Index() 
    { 
     // TODO: Use the business operation here. 
    } 
} 

Puede ver cómo las interfaces nos permiten proporcionar un acoplamiento débil entre las capas. Toda la plomería se realiza mediante el marco DI y todo es transparente y fácilmente comprobable por unidad.

+0

Darin, Dentro de este contexto, ¿cuál es la mejor manera de acceder a varios repositorios de un solo servicio? También, ¿podría decirme cuál sería la solución para una IoC/DI? – Chandu

+0

¡Gracias, Darin! –

+0

Gracias por la explicación Darin – Chandu

1

Creo que su super repositorio acaba de romper el Principio de Responsabilidad Individual. Dejaría el repositorio lo más simple posible (patrón KISS;) y crearía otra capa entre los controladores y el repositorio, e.q. capa de negocios.

Para reutilizar y simplificar el código de echar un vistazo a la inyección de dependencias (implementar COI)

En realidad, yo sugeriría a echar un vistazo a los principios sólidos.

2

Utilizaría un enfoque de diseño impulsado por el dominio. Un muy buen libro sobre DDD es el siguiente: .NET Domain-Driven Design with C#: Problem-Design-Solution. Busque también Fowlers Enterprise Patterns y Evans Domain Driven Design books. La idea básica es que un repositorio es básicamente infraestructura. Toda la lógica de dominio va a su modelo.

Ejemplo de un método de repositorio es el siguiente:

public void InsertAddresse(Company company) 
{ 
    foreach (Address address in company.Addresses) 
    { 
     this.InsertAddress(address, company.Key, (company.HeadquartersAddress == address)); 
    } 
} 

Por otro lado, un objeto de modelo se parece a esto:

public class Contact : Person, IAggregateRoot, IHasAddresses 
{ 
    private string jobTitle; 
    private string email; 
    private string phoneNumber; 
    private string mobilePhoneNumber; 
    private string faxNumber; 
    private string remarks; 
    private Company currentCompany; 
    private IList<Address> addresses; 

    public Contact() 
     : this(null) 
    { 
    } 

    public Contact(object key) 
     : this(key, null, null) 
    { 
    } 

    public Contact(object key, string firstName, string lastName) 
     : base(key, firstName, lastName) 
    { 
     this.jobTitle = string.Empty; 
     this.email = string.Empty; 
     this.phoneNumber = string.Empty; 
     this.mobilePhoneNumber = string.Empty; 
     this.faxNumber = string.Empty; 
     this.remarks = string.Empty; 
     this.currentCompany = null; 
     this.addresses = new List<Address>(); 
    } 

    public string JobTitle 
    { 
     get { return this.jobTitle; } 
     set { this.jobTitle = value; } 
    } 

    public string Email 
    { 
     get { return this.email; } 
     set { this.email = value; } 
    } 

    public string PhoneNumber 
    { 
     get { return this.phoneNumber; } 
     set { this.phoneNumber = value; } 
    } 

    public string MobilePhoneNumber 
    { 
     get { return this.mobilePhoneNumber; } 
     set { this.mobilePhoneNumber = value; } 
    } 

    public string FaxNumber 
    { 
     get { return this.faxNumber; } 
     set { this.faxNumber = value; } 
    } 

    public string Remarks 
    { 
     get { return this.remarks; } 
     set { this.remarks = value; } 
    } 

    public Company CurrentCompany 
    { 
     get { return this.currentCompany; } 
     set { this.currentCompany = value; } 
    } 

    public IList<Address> Addresses 
    { 
     get { return this.addresses; } 
    } 

    protected override void Validate() 
    { 
     //some logic here 
    } 

    protected override BrokenRuleMessages GetBrokenRuleMessages() 
    { 
     return new ContactRuleMessages(); 
    } 
} 
+0

¡Gracias fue realmente perspicaz! –

Cuestiones relacionadas