Domanda

The question relates to the injection of repositories and utility classes in an entity.

Background

The repository isn't directly used by the entity, but instead is passed through to a strategy which needs to enforce certain business rules.

The utility classes in question help with the validation of the model and image handling functionality. The validation utility applies JSR 303 validation to the model which checks that the entity is valid when created (custom JSR 303 annotations are used for certain business rules too). The image utility is called once the Order is saved (post persist) and uploads the image related to the order. This is done post persist as the ID of the Order in question is needed.

Question

All these dependencies injected into the entity don't feel right. The dilema is whether to move them all (or some, which ones?) out of the domain object and move them elsewhere? (if so what would be the right place?) or whether this is a case of analysis paralysis?

For example, the strategy ensures certain business rules are met. Should that be taken out because it needs the repository? I mean it needs to be run whenever the entity performs that update, so do I really want to lose that encapsulation?

public class OrderFactory {

  // This could be autowired
  private IOrderRepository orderRepository;
  private ValidationUtils validationUtils;
  private ImageUtils imageUtils;

  public OrderFactory( IOrderRepository orderRepository, ValidationUtils validationUtils, ImageUtils imageUtils ) {
    this.orderRepository = orderRepository;
    this.validationUtils = validationUtils;
    this.imageUtils = imageUtils;
  }

  public Order createOrderFromSpecialOrder( SpecialOrderDTO dto ) {
    Order order = (dto.hasNoOrderId()) ? new Order() : orderRepository.findOrderById(dto.getOrderId());

    order.updateFromSpecialOrder( orderRepository, validationUtils, imageUtils, dto.getSpecialOrderAttributes(), dto.getImage());

    return order;
  }
}


public class Order {
  private IOrderRepository orderRepository;
  private ValidationUtils validationUtils;
  private ImageUtils imageUtils;
  private byte[] image;

  protected Order() {}

  protected void updateFromSpecialOrder( IOrderRepository orderRepository, ValidationUtils validationUtils, ImageUtils imageUtils, ISpecialOrderAttributes attrs, byte[] image ) {
    this.orderRepository = orderRepository;
    this.imageUtils = imageUtils;

    // This uses the orderRepository to do some voodoo based on the SpecialOrderAttributes
    SpecialOrderStrategy specialOrderStrategy = new SpecialOrderStrategy( orderRepository );
    specialOrderStrategy.handleAttributes( attrs );

    this.coupon = coupon;
    this.image = image;

    validationUtils.validate( this );
  }

  @PostPersist
  public void postPersist() {
    if( imageUtils != null ) imageUtils.handleImageUpload( image, id, ImageType.Order );
  }
}
È stato utile?

Soluzione

What you are looking for is a domain service that plays a coordinating role and it depends on the aforementioned services/repositories. It's a classic mistake to try to stuff too much responsibility into an aggregate due to this twisted view of what invariants really are. Post processing might benefit from a domain event to kick it off (either in or out of process - you've given me too little to go on here). You also might want to assign identifiers from the outside, or allocate one as part of the domain service's method execution. As for the validation, ditch the attributes and hand roll (if they really are about the entity). YMMV.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top