Как правильно публиковать события домена DDD с весны? - PullRequest
1 голос
/ 04 октября 2019

Я пытаюсь реализовать дизайн, управляемый доменом, в моем проекте. Вот мой базовый Aggregate класс:

public abstract class UUIDAggregate {
    private final DomainEventPublisher domainEventPublisher;

    protected void publish(DomainEvent domainEvent) {
        domainEventPublisher.publish(domainEvent);
    }
}

Допустим, у нас есть UserAccount совокупность:

public class UserAccount extends UUIDAggregate {
    private String email;
    private String username;
    private String password;
    private String firstName;
    private String lastName;

    public void update() {
        publish(new DomainEventImpl());
    }
}

Вот мой DomainEventPublisher:

public interface DomainEventPublisher {
   void publish(DomainEvent event);
}

Вот DomainEventPublisherImpl:

@Component
public class DomainEventPublisherImpl implements DomainEventPublisher{
    @Autowired
    private ApplicationEventPublisher publisher;

    public void publish(DomainEvent event){
        publisher.publishEvent(event);
    }
}

Теперь это кажется хорошей идеей, домен отделен от реализации, но это не работает. DomainEventPublisher не может быть Autowired, поскольку UUIDAggregate не является @Component или @Bean. Одним из решений было бы создать DomainService и опубликовать там событие, но это похоже на утечку домена в службу домена, и если я пойду таким образом, я пойду к анемичной модели. Также я могу передать DomainEventPublisher в качестве параметра для каждого агрегата, но это также не кажется хорошей идеей.

1 Ответ

2 голосов
/ 06 октября 2019

Одной из идей было бы создать фабрику для доменных объектов:

@Component
class UserAccountFactoryImpl implements UserAccountFactory {
    @Autowired
    private DomainEventPublisher publisher;

    @Override
    public UserAccount newUserAccount(String email, String username, ...) {
        return new UserAccount(email, username, ..., publisher);
    }
}

Тогда ваш код, создающий объект домена, "не имеет издателей":

UserAccount userAccount = factory.newUserAccount("john@example.com", ...);

Или вы можетеНемного измените дизайн публикации событий:

public abstract class UUIDAggregate {
    private final List<DomainEvent> domainEvents = new ArrayList<>();

    protected void publish(DomainEvent domainEvent) {
        domainEvents.add(domainEvent);
    }
    public List<DomainEvent> domainEvents() {
        return Collections.unmodifiableList(domainEvents);
    }
}

@Component
class UserAccountServiceImpl implements UserAccountService {
    @Autowired
    private DomainEventPublisher publisher;

    @Override
    public void updateUserAccount(UserAccount userAccount) {
        userAccount.update();

        userAccount.domainEvents().forEach(publisher::publishEvent);
    }
}

Это отличается от вашего предложения: служба публикует события, но не создает , затем- логика остается в доменном объекте.

Кроме того, вы можете изменить своего издателя, чтобы свести к минимуму стандартный код:

public interface DomainEventPublisher {
   void publish(UUIDAggregate aggregate);
}
...