Один сервис для каждого субъекта? - PullRequest
1 голос
/ 07 июля 2011

Опять же - я запутался в вещах DDD:)

У меня есть архитектура (я все еще над ней работаю), которая вкратце выглядит так:

DataLayer:
 EntityDao -> Implementing domain layer interfaces (NHibernate)
DomainLayer:
 EntityRepository -> Repository for each entity with injected Dao
 DomainObjects/Entitys -> Some logic
UI
 ASP.Net MVC

И я сейчас нахожусь в той точке, где я чувствую, что создаю и использую какой-то класс Service. У меня есть несколько вопросов с этим:

1.Можно ли создать хотя бы одну службу для каждого объекта сущности / домена?

2.a. Должны ли службы иметь метод запроса, такой как Find, FIndAll, FindAll (LINQQuery)?

2.b. Должен ли я прекратить использовать Repositorys в верхних слоях (UI) для получения наборов ("Find" -подобных методов) сущностей и начать использовать только сервисы?

3.Если ответ на 2 вопроса - Нет, должен ли я использовать службы и репозиторий параллельно (когда в пользовательском интерфейсе мне просто нужно получить все объекты, я использую Repository.FindAll, когда мне нужно получить некоторый «логический» список я использую метод Service.FindXXX)?

4. Как-то мне кажется, что репозитории не вписываются в слой домена - нужно ли их как-то разделять, а в DOMAIN оставлять только объекты, относящиеся к домену, такие как Entity и Services? Если да - приведите пример структуры, как этого добиться.

Примеры некоторых объектов:

ДАО:

public class NHibernateDao<T> : IDao<T>
{
    public NHibernateDao() { }

    public T Get(object id)
    {
        T entity = (T)NHibernateSession.Get(entityType, id);
        return entity;
    }
    public T Load(object id)
    {
        T entity = (T)NHibernateSession.Load(entityType, id);
        return entity;
    }
    public virtual T Update(T entity)
    {
        NHibernateSession.Update(entity);
        return entity;
    }
    ...

Repository:

public class BaseRepository<T>:IRepository<T>
{
    private DataInterfaces.IDao<T> mDao;

    public virtual T Get(object id)
    {
        return mDao.Get(id);
    }
    public virtual void Delete(T entity)
    {
        mDao.Delete(entity);
    }
    public virtual T Update(T entity)
    {
        return mDao.Update(entity);
    }
    public virtual IQueryable<T> FindAll()
    {
        return mDao.FindAll();
    }
    ...

Доменные объекты, на данный момент это в основном контейнер get / set - основанием для этого вопроса является удаление этой анемичной модели.

Ответы [ 2 ]

7 голосов
/ 08 июля 2011

1. Один сервис на одно лицо?

Нет. Вам не нужно создавать один сервис для одного объекта. В DDD вы создаете сервисы для операций, которые не отображаются естественным образом на один объект (или объект значения). Хороший сервис (от Эванс ):

  • Операция относится к концепции домена, которая не является естественной частью сущности или объекта значения.
  • Интерфейс определяется в терминах элементов домена.
  • Операция без сохранения состояния

Таким образом, служба может потреблять много сущностей, и может быть много сущностей, которые вообще не потребляются одной службой.

2a. Должны ли сервисы иметь методы «запроса» (..)?

Нет. Вообще говоря, это методы репозитория, которые не размещаются на сервисах. Однако в службе могут быть операции, которые возвращают набор сущностей.

2b. Должен ли я прекратить использование репозиториев на верхних уровнях (UI) для получения наборов ("Find" -подобных методов) сущностей и начала использовать только сервисы?

Это может быть хорошей идеей. Часто, когда приложение использует множество репозиториев на уровне пользовательского интерфейса, пользовательский интерфейс выполняет операции над доменом для нескольких объектов. Эти операции обычно должны быть реализованы на уровне домена; либо в самих сущностях, либо в службах.

3. Должен ли я использовать службы и репозитории параллельно с пользовательским интерфейсом?

Лучше нет, см. Выше; хотя в некоторых случаях вы можете быстро создать часть своего пользовательского интерфейса, сделав это.

4. Почему-то я чувствую, что репозитории не вписываются в слой домена ...

Вы правы, вы должны только размещать интерфейсы репозитория в домене. См. Ответ Костассоида для примера.

6 голосов
/ 07 июля 2011

Мои мысли:

  1. Сервисы предоставляют интерфейс верхнего уровня для бизнес-логики.Как правило, вы должны скрывать детали реализации вашего уровня домена (которая ниже) за его методами, в основном командами или запросами.Хороший способ мышления может заключаться в том, чтобы назвать ваши методы обслуживания после сценариев использования или пользовательских историй.И вам не следует предоставлять больше функций, которые требуются сервисным клиентам (UI).

2a.Если вашему пользовательскому интерфейсу нужны все данные от объектов какого-либо типа, тогда да, в противном случае нет.И FindAll () вряд ли является вариантом использования.

2b.Вам следует использовать Репозитории из ваших Сервисов, это фактически единственное место, где вы должны его использовать.

3 см. 2b.

4 Да.Вы должны оставить интерфейсы для репозиториев в вашем Домене, но реализация должна быть в Доступе к данным.Тогда вы можете склеить все с некоторым контейнером IoC.Может быть так:

//in domain
public interface IUserRepository {
    User GetById(Guid id);
}
//in data access
public class UserRepository : IUserRepository
{
    public UserRepsitory(/* some orm specific dependencies */) { }
    public User GetById(Guid id) { /* implementation */ }
}
...