C# Service Layer Design Pattern

旧城冷巷雨未停 提交于 2019-12-02 17:44:07

Email service should not be aware of services like OrderService, you need Mediator to work with both Email&&Order services so they would be decoupled, or Adapter to adapt IOrder to 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)
    {
    }
}

Mediator:

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently

Adapter:

The adapter pattern (often referred to as the wrapper pattern or simply a wrapper) is a design pattern that translates one interface for a class into a compatible interface

Take a look at Domain Driven Design. DDD moves most of the logic into the entities (Order, Email) and lets them use the repositories.

1) Should the service be reproducing the CRUD methods, as it appears we may be reproducing code with no real benefit. Or should the UI call the repositories directly?

A service in DDD is used when you find yourself writing business logic outside the entities.

2) What happens when a service needs to call another service. In our example above if Email Service needs to get all the orders, do we inject the order service into the Email service?

Inject it in the constructor. However, the order service should send an email, not the other way around.

The DDD approach would be to create a OrderNotificationService which takes the domain event OrderCreated and composes an email which it sends through the EmailService

Update

You missunderstood me. Duplicated logic is never good. I would not put a method in my service named GetAll when my repository has one. Neither would I put that method in my entity either.

Example code:

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

Order.Send() should create a domain event that the OrderNotificationService can catch.

Update2

Repository.Create is just a factory method (google factory method pattern) to get all domain model creations in one place. It do not do anything in the db (although it could in future versions).

As for order.Save it would use the repository to save all order lines, the order itself or anything else that would be needed.

What I would have done is

  1. Not call repositories directly from the UI, but call the service instead and service should use the repository,

  2. I would the call the method of Order repository from Email service, this way I would have only inject OrderRepository to Email Service (not Order Service)

hanz

you can use adapter pattern or using DI tools

public class EmailService
{
    private IOrderRepository _orderservice = null;

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

    public void SendEmails()
    {
        _orderService.GetAll();
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!