C#服务层设计模式

时间:2012-02-21 11:55:55

标签: c# design-patterns service tdd repository

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

请参阅下面的基本架构构思。我们将使用接口来描述存储库并将它们注入服务层以删除任何依赖项。然后使用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
    }
}

我们在找到最佳前进方法时遇到了一些问题。

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

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

希望这是有道理的

4 个答案:

答案 0 :(得分:3)

电子邮件服务不应该了解OrderService等服务,您需要Mediator才能使用电子邮件和订单服务,以便将它们分离,或Adapter以适应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通过防止对象引用来促进松散耦合   彼此明确地,它可以让你改变他们的互动   独立地

<强>适配器

  

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

答案 1 :(得分:2)

看一下Domain Driven Design。 DDD将大部分逻辑移动到实体(OrderEmail)中,并允许它们使用存储库。

  

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

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

  

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

在构造函数中注入它。但是,订单服务应该发送电子邮件,而不是相反。

DDD方法是创建一个OrderNotificationService,其中包含域事件OrderCreated并撰写通过EmailService发送的电子邮件

<强>更新

你误解了我。重复逻辑永远不会好。当我的存储库有一个方法时,我不会在我的服务中放置一个名为GetAll的方法。我也不会将该方法放在我的实体中。

示例代码:

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

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

<强> UPDATE2

Repository.Create只是一种工厂方法(谷歌factory method pattern),可以在一个地方获得所有域模型创建。它在db中没有做任何事情(虽然它可以在将来的版本中使用)。

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

答案 2 :(得分:0)

我要做的是

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

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

答案 3 :(得分:0)

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

public class EmailService
{
    private IOrderRepository _orderservice = null;

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

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