Шаблон проектирования сервисного уровня C # - PullRequest
11 голосов
/ 21 февраля 2012

Мы смотрим на создание нового проекта и хотим исследовать его с использованием шаблонов уровней 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, как представляется, мы можем воспроизводить код без реальной выгоды.Или пользовательский интерфейс должен вызывать репозитории напрямую?

2) Что происходит, когда службе требуется вызвать другую службу.В нашем примере выше, если службе электронной почты нужно получить все заказы, вводим ли мы службу заказов в службу электронной почты?

Надеюсь, это имеет смысл

Ответы [ 4 ]

3 голосов
/ 21 февраля 2012

Служба электронной почты не должна знать о таких службах, как OrderService, вам необходимо Посредник для работы с обеими службами Email && Order, чтобы они были разъединены, или Адаптер для адаптации IOrder к 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)
    {
    }
}

Посредник :

Определите объект, который инкапсулирует, как взаимодействует набор объектов.Посредник способствует слабой связи, не позволяя объектам явно ссылаться друг на друга, и позволяет независимо изменять их взаимодействие

Адаптер :

Адаптершаблон (часто называемый шаблоном оболочки или просто оболочкой) - это шаблон проекта, который переводит один интерфейс для класса в совместимый интерфейс

2 голосов
/ 21 февраля 2012

Взгляните на дизайн, управляемый доменом. DDD перемещает большую часть логики в сущности (Order, Email) и позволяет им использовать репозитории.

1) Если служба воспроизводит методы CRUD, как мы видим, мы можем воспроизводить код без реальной выгоды. Или пользовательский интерфейс должен вызывать хранилища напрямую?

Служба в 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 - это просто фабричный метод (google factory method pattern), чтобы получить все создания модели домена в одном месте. Он ничего не делает в БД (хотя мог бы в будущих версиях).

Что касается порядка. Сохраните его, используя хранилище для сохранения всех строк заказа, самого заказа или чего-либо еще, что потребуется.

0 голосов
/ 08 июля 2013

вы можете использовать шаблон адаптера или инструменты DI

public class EmailService
{
    private IOrderRepository _orderservice = null;

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

    public void SendEmails()
    {
        _orderService.GetAll();
    }
}
0 голосов
/ 21 февраля 2012

Я бы сделал следующее:

  1. Не вызывайте репозитории напрямую из пользовательского интерфейса, а вместо этого вызывайте сервис, и сервис должен использовать репозиторий,

  2. Я бы вызвал метод репозитория заказов из сервиса электронной почты, таким образом, я бы только вводил репозиторий заказов в сервис электронной почты (не сервис заказов)

...