C#服务层设计模式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9377172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 07:06:32  来源:igfitidea点击:

C# Service Layer Design Pattern

c#design-patternsservicetddrepository

提问by user1223218

We are looking into creating a new project and are wanting to explore using the Repository and Service layer patterns, the aim to is create loosely coupled code which is fully testable using mock repositories.

我们正在考虑创建一个新项目,并希望使用存储库和服务层模式进行探索,目的是创建松散耦合的代码,使用模拟存储库完全可测试。

Please see below the basic architecture idea. We will be using interfaces to describe the repositories and inject these into the service layers to remove any dependencies. Then using autofac we will wire up the services at runtime.

请参阅下面的基本架构思想。我们将使用接口来描述存储库并将它们注入服务层以删除任何依赖项。然后使用 autofac 我们将在运行时连接服务。

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

There are a few questions which we are having trouble finding out the best way forward.

有几个问题我们很难找到最好的前进方向。

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?

1) 服务是否应该重现 CRUD 方法,因为看起来我们可能在重现没有真正好处的代码。还是 UI 应该直接调用存储库?

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?

2)当一个服务需要调用另一个服务时会发生什么。在我们上面的例子中,如果电子邮件服务需要获取所有订单,我们是否将订单服务注入电子邮件服务?

Hope this makes sense

希望这是有道理的

回答by sll

Email service should not be aware of services like OrderService, you need Mediatorto work with both Email&&Order services so they would be decoupled, or Adapterto adapt IOrderto IEmail:

电子邮件服务不应该知道像OrderService服务,你需要调解员与双方电邮&&订购服务方面的工作,这样他们就被分离,或适配器适应IOrderIEmail

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

适配器模式(通常称为包装器模式或简称为包装器)是一种将类的一个接口转换为兼容接口的设计模式

回答by Jayanga

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)

  1. 不直接从 UI 调用存储库,而是调用服务,服务应使用存储库,

  2. 我会从电子邮件服务调用订单存储库的方法,这样我只会将 OrderRepository 注入电子邮件服务(而不是订单服务)

回答by jgauffin

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

看看领域驱动设计。DDD 将大部分逻辑移到实体 ( Order, Email) 中并让它们使用存储库。

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?

1) 服务是否应该重现 CRUD 方法,因为看起来我们可能在重现没有真正好处的代码。还是 UI 应该直接调用存储库?

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

当您发现自己在实体之外编写业务逻辑时,将使用 DDD 中的服务。

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?

2)当一个服务需要调用另一个服务时会发生什么。在我们上面的例子中,如果电子邮件服务需要获取所有订单,我们是否将订单服务注入电子邮件服务?

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 OrderNotificationServicewhich takes the domain event OrderCreatedand composes an email which it sends through the EmailService

DDD 方法是创建一个OrderNotificationService接受域事件OrderCreated并撰写电子邮件,然后通过EmailService

Update

更新

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

你误会了我的意思。重复的逻辑从来都不是好的。GetAll当我的存储库有一个方法时,我不会在我的服务中放置一个方法。我也不会将该方法放入我的实体中。

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 OrderNotificationServicecan catch.

Order.Send()应该创建一个OrderNotificationService可以捕获的域事件。

Update2

更新2

Repository.Createis 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).

Repository.Create只是一种工厂方法(google factory method pattern),可以在一个地方获取所有域模型创建。它在数据库中不做任何事情(尽管它可以在未来的版本中)。

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

至于 order.Save 它将使用存储库来保存所有订单行、订单本身或任何其他需要的东西。

回答by hanz

you can use adapter pattern or using DI tools

您可以使用适配器模式或使用 DI 工具

public class EmailService
{
    private IOrderRepository _orderservice = null;

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

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