2012-02-21 23 views
10

Estamos buscando crear un nuevo proyecto y queremos explorar utilizando los patrones de capa de repositorio y servicio, el objetivo es crear código ligeramente acoplado que sea totalmente comprobable mediante repositorios simulados.C# Patrón de diseño de capa de servicio

Consulte a continuación la idea de la arquitectura básica. Usaremos interfaces para describir los repositorios e inyectarlos en las capas de servicio para eliminar cualquier dependencia. Luego, usando autofac conectaremos los servicios en tiempo de ejecución.

public interface IOrderRepository 
{ 
    IQueryable<Order> GetAll(); 
} 

public class OrderRepository : IOrderRepository 
{ 
    public IQueryable<Order> GetAll() 
    { 
     return new List<Order>().AsQueryable(); 
    } 
} 

public class OrderService 
{ 
    private readonly IOrderRepository _orderRepository; 

    public OrderService(IOrderRepository orderRepository) 
    { 
     _orderRepository = orderRepository; 
    } 

    public IQueryable<Order> GetAll() 
    { 
     return _orderRepository.GetAll(); 
    } 
} 

public class EmailService 
{ 
    public void SendEmails() 
    { 
     // How do I call the GetAll method from the order serivce 
     // I need to inject into the orderService the repository to use 
    } 
} 

Hay algunas preguntas que tenemos problemas para encontrar la mejor manera de avanzar.

1) En caso de que el servicio esté reproduciendo los métodos CRUD, ya que parece que estamos reproduciendo código sin ningún beneficio real. ¿O debería la interfaz de usuario llamar a los repositorios directamente?

2) Qué sucede cuando un servicio necesita llamar a otro servicio. En nuestro ejemplo anterior, si el servicio de correo electrónico necesita obtener todos los pedidos, ¿inyectamos el servicio de pedido en el servicio de correo electrónico?

la esperanza que esto tiene sentido

+0

servicio de correo electrónico no debe estar al tanto de los servicios como OrderService, es necesario Mediador para trabajar tanto con los servicios de correo electrónico && orden de modo que se desacoplan – sll

+0

¿Qué hace su servicio de pedidos ¿hacer? ¿Simplemente encapsular el OrderRepository? O hace más que eso, por el aspecto de tu código, parece una capa redundante. – gideon

+0

Haría otra pregunta. ¿Es bueno exponer IQueryable fuera del límite del repositorio? Para mi no. Es una abstracción con goteras. –

Respuesta

2

servicio de correo electrónico no debe estar al tanto de los servicios como OrderService, necesita Mediator trabajar con ambos E-mail & & servicios de pedidos por lo que se desacoplan, o Adapter para adaptarse IOrder a IEmail:

IEnumerable<IOrder> orders = orderService.GetAll(); 

// TODO: Create emails from orders by using OrderToEmailAdaptor 
IEnumerable<IEmail> emails = ... 
emailService.SendEmails(emails); 

public sealed class EmailService 
{ 
    public void SendEmails(IEnumerable<IEmail> emails) 
    { 
    } 
} 

Mediador:

Define un objeto que encapsula cómo interactúan un conjunto de objetos. mediador promueve la articulación flexible manteniendo los objetos de referirse a entre sí de forma explícita, y se le permite variar su interacción independientemente

adaptador:

El adapter (a menudo referido como el patrón de envoltura o simplemente un envoltorio) es un patrón de diseño que traduce una interfaz para una clase en una interfaz compatible

+1

+1 Por mediación, pensé que te estabas refiriendo al patrón del mediador por un segundo, ¡pero esto es correcto y simple! :) No creo que se requiera un servicio de pedido, sin embargo, el repositorio ya se encarga de desacoplar ** cómo ** se recuperan los pedidos? – gideon

+0

Hola, gracias por tus comentarios. En el ejemplo anterior, ¿quién llamaría al método SendEmails? ¿Todavía no necesitarías un código en algún lugar que reciba los pedidos y luego llame al servicio de correo electrónico? – user1223218

+0

@ user1223218: esto podría ser un mediador. Teniendo en cuenta los requisitos, ¿quién es el que determina cuándo es el momento de llamar a SendEmails() ?, ¿es algún controlador de eventos? – sll

0

Lo que yo he hecho es

  1. no llama a repositorios directamente desde la interfaz de usuario, pero llamar al servicio en lugar y el servicio debe utilizar el repositorio,

  2. lo haría la llamada del método de la Orden repositorio de servicio de correo electrónico, así que tendría que inyectar solamente OrderRepository al servicio de correo electrónico (no orden de servicio)

+0

Gracias por su respuesta, si el servicio de correo electrónico utiliza el repositorio directamente, no corremos el riesgo de que ocurran diferentes acciones, ya que GetAll() puede cambiarse en el servicio para funcionar de manera diferente a GetAll() desde el repositorio. Gracias – user1223218

2

Tome un vistazo a Domain Driven Design. DDD mueve la mayor parte de la lógica a las entidades (Order, Email) y les permite usar los repositorios.

1) En caso de que el servicio esté reproduciendo los métodos CRUD, ya que parece que podemos estar reproduciendo código sin ningún beneficio real. ¿O debería la interfaz de usuario llamar a los repositorios directamente?

Un servicio en DDD se usa cuando se encuentra escribiendo lógica comercial fuera de las entidades.

2) ¿Qué sucede cuando un servicio necesita llamar a otro servicio? En nuestro ejemplo anterior, si el servicio de correo electrónico necesita obtener todos los pedidos, ¿inyectamos el servicio de pedido en el servicio de correo electrónico?

Inyectar en el constructor. Sin embargo, el servicio de pedido debe enviar un correo electrónico, no al revés.

El enfoque DDD sería la creación de un OrderNotificationService que tiene el evento dominio OrderCreated y compone un correo electrónico que se envía a través de la actualización de EmailService

Me Missunderstood. La lógica duplicada nunca es buena. No pondría un método en mi servicio llamado GetAll cuando mi repositorio tiene uno. Tampoco pondría ese método en mi entidad tampoco.

código Ejemplo:

var order = repository.Create(userId); 
order.Add(articleId, 2); 
order.Save(); // uses the repository 

Order.Send() debe crear un evento de dominio que el OrderNotificationService puede coger.

Update2

Repository.Create es sólo un método de fábrica (google factory method pattern) para obtener todas las creaciones modelo de dominio en un solo lugar. No hace nada en el db (aunque podría en versiones futuras).

En cuanto a la orden. Guardar usaría el repositorio para guardar todas las líneas de pedido, el orden en sí o cualquier otra cosa que se necesitaría.

+0

Hola, gracias por tu respuesta. Si el orden fuera tener métodos como Order.GetAll() no está acoplado, ¿cómo ordenaría qué repositorio usar? Gracias – user1223218

+0

+1 - OrderNotificationService definitivamente suena más como la forma correcta para mí. –

+0

@ user1223218: Lee mi actualización. – jgauffin

0

puede utilizar adapter o el uso de herramientas DI

public class EmailService 
{ 
    private IOrderRepository _orderservice = null; 

    public EmailService(IOrderService orderservice) 
    { 
     _orderservice = orderservice; 
    } 

    public void SendEmails() 
    { 
     _orderService.GetAll(); 
    } 
} 
Cuestiones relacionadas