How to enforce constraint such as any field (or specific field) must not change if entity is in some state?

前端 未结 3 1871
名媛妹妹
名媛妹妹 2021-01-03 09:03

I\'m trying to use DDD in my current project (c#, mvc, nhibernate, castle) and I\'m thinking of best way to check a constraint that says any field (or specific field) must n

3条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-01-03 09:19

    Domain objects in DDD are 'self validating'. In other words, it is not possible for client code to break domain rules because objects enforce their internal invariants. For example:

    public class Invoice {
        private Money _amount;
        private InvoiceState _state;
    
        public void ChangeAmount(Money newAmount) {
            if(_state == State.Booked) {
                throw new InvalidOperationException(
                          "Unable to change amount for booked invoice.");
            }
            _amount = newAmount;
        }
    
        // Methods like this can be used by external code (UI) to check business
        // rules upfront, to avoid InvalidOperationException.
        public Boolean CanChangeAmount() {
            if(_state == State.Booked) {
                return false;
            }
            return true;
        }
    }
    

    Another example from DDD sample:

      public HandlingEvent(final Cargo cargo,
                           final Date completionTime,
                           final Date registrationTime,
                           final Type type,
                           final Location location,
                           final Voyage voyage) {
    
        ...
    
        if (type.prohibitsVoyage()) {
          throw new IllegalArgumentException(
                           "Voyage is not allowed with event type " + type);
        }
    

    Never allow your UI framework treat domain object as dumb data container. Unfortunately this is encouraged by a lot examples on the internet and C#'s emphasis on getters and setters. If you change object state without enforcing business rules you will eventually end up with 'corrupted' objects. This is especially true for NHibernate because its Session 'remembers' all objects and will happily dump them into database on next commit or flush. But this is just a technicality, the main reason is that you need to be able to reason about Invoice related business rules just by looking at Invoice class. Also note that the code should be based on Ubiquitous Language. You should see words like 'Invoice', 'Booked', 'Amount' instead of generic 'Field', 'Property', 'Validator'.

    UPDATE: empi, thank you for restating your problem. You might want to open a new question. This is the quote with my emphasis

    As I said in one of my comments - this question is a part of a bigger problem I'm having. I'm looking for a standard way to define domain logic and constraints only in the domain and then translate it to gui and other layers. I don't see any common pattern to the following very common demand: the domain states that field cannot be edited and this rule is automatically converted to gui logic that disables the field and makes it readonly. I'm looking for sample solution in mvc stack. I feel like I'm reinventing the wheel and most developers just give up and duplicate the logic in gui

    I think that you looking for a way to state everything in domain and then 'generate' UI. Something like Naked Objects for MVC? I never used this approach but I doubt that generated UI would ever win beauty or usability contest. In my opinion there will always be some 'restating' of business logic in UI. Some domain invariants are too complex, involve multiple fields, require repository and maybe even external services. I'm not sure that it is possible to generate high quality user interface automatically. I think that attempts to do this may start bending your model to conform to the UI infrastructure.

提交回复
热议问题