DDD: Удалить в хранилище или удалить в сущности?

Очень простой вариант использования, реализованный с использованием DDD и Java.

У меня есть FooEntity и FooRepository. У сущности есть метод удаления, который проверяет определенное состояние, чтобы проверить, безопасно ли быть удаленным, и в случае, если это имеет значение true, вызывает удаление в хранилище, которое внедряется в сущность.

Пока все хорошо, но что произойдет, если кто-нибудь вызовет метод удаления непосредственно в хранилище? Тогда проверка не будет выполнена.

Размещение проверки в хранилище решило бы проблему, но это было бы явно неправильно, так как это потребовало бы раскрытия внутреннего состояния объекта.

Что мне не хватает?

public class FooEntity {

  @inject
  FooRepository fooRepository;

  private Boolean canBeDeleted;

  public void delete(){
    if (canBeDeleted){
      fooRepository.delete(this);
    }
    throw new CannotBeDeletedException();
  }
}

public class FooRepository {

  @inject
  FooDAO fooDAO;

  public void delete(FooEntity fooEntity){
    fooDAO.delete(fooEntity.getId());
  }
}

3 ответа

Не раскрывайте внутреннее состояние, предоставляйте метод, подобный isDeletable(), для сущности. Удаление хранилища может вызывать entity.isDeletable() перед удалением и вызывать исключение, если вы пытаетесь удалить объект, который нельзя удалить. Таким образом, вы разделяете проблемы. Сущность знает домен о своей "удаляемости", в то время как репо знает, как удалить сущность.

Пример кода хорош как есть (за исключением того, что странно иметь DAO внутри класса репозитория, поскольку "хранилище" - это просто более абстрактное имя для той же концепции, что и DAO).

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

Хранилище должно заниматься только удалением данного экземпляра сущности из набора постоянных сущностей. Он не может иметь логику для проверки, разрешено ли удаление объекта или нет, даже если isDeletable() Метод находится в классе сущности.

Я бы поставил функцию удаления в доменной службе.

public class FooService {

  @inject
  FooRepository fooRepository;

  public void delete(Foo foo) {

    if( /* insert validation stuff here to check if foo can be deleted */ ) {
      fooRepository.delete(foo);
    }
 }

Однако, как я это делаю, я обычно использую ValueObject для представления идентичности сущности. Например

public class FooId() {

    String foodId;

    public String FooId(String fooId) {
       this.foodId = foodId;
    }
}

public class Foo() {

    FooId id;

    /* other properties */
}

Затем я бы пересмотрел FooService, чтобы:

public class FooService {

  @inject
  FooRepository fooRepository;

  public void delete(FooId fooId) {

    foo = fooRepository.retrieve(fooId);

    if( /* insert validation stuff here to check if foo can be deleted */ ) {
      fooRepository.delete(foo);
    }
 }

Чтобы удалить foo (при условии, что fooId был передан командой из пользовательского интерфейса:

 fooService.delete(fooId);

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

Другие вопросы по тегам