Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I still looking best practice for domain model validation. Is that good to put the validation in constructor of domain model ? my domain model validation example as follows:

public class Order
 {
    private readonly List<OrderLine> _lineItems;

    public virtual Customer Customer { get; private set; }
    public virtual DateTime OrderDate { get; private set; }
    public virtual decimal OrderTotal { get; private set; }

    public Order (Customer customer)
    {
        if (customer == null)
            throw new  ArgumentException("Customer name must be defined");

        Customer = customer;
        OrderDate = DateTime.Now;
        _lineItems = new List<LineItem>();
    }

    public void AddOderLine //....
    public IEnumerable<OrderLine> AddOderLine { get {return _lineItems;} }
}


public class OrderLine
{
    public virtual Order Order { get; set; }
    public virtual Product Product { get; set; }
    public virtual int Quantity { get; set; }
    public virtual decimal UnitPrice { get; set; }

    public OrderLine(Order order, int quantity, Product product)
    {
        if (order == null)
            throw new  ArgumentException("Order name must be defined");
        if (quantity <= 0)
            throw new  ArgumentException("Quantity must be greater than zero");
        if (product == null)
            throw new  ArgumentException("Product name must be defined");

        Order = order;
        Quantity = quantity;
        Product = product;
    }
}

Thanks for all of your suggestion.

share|improve this question
add comment

3 Answers

There's an interesting article by Martin Fowler on that subject that highlights an aspect most people (including me) tend to overlook:

But one thing that I think constantly trips people up is when they think object validity on a context independent way such as an isValid method implies.

I think it's much more useful to think of validation as something that's bound to a context - typically an action that you want to do. Is this order valid to be filled, is this customer valid to check in to the hotel. So rather than have methods like isValid have methods like isValidForCheckIn.

From this follows that the constructor should not do validation, except perhaps some very basic sanity checking shared by all contexts.

Again from the article:

In About Face Alan Cooper advocated that we shouldn't let our ideas of valid states prevent a user from entering (and saving) incomplete information. I was reminded by this a few days ago when reading a draft of a book that Jimmy Nilsson is working on. He stated a principle that you should always be able to save an object, even if it has errors in it. While I'm not convinced that this should be an absolute rule, I do think people tend to prevent saving more than they ought. Thinking about the context for validation may help prevent that.

share|improve this answer
    
Thank goodness someone said this. Forms that have 90% of the data but won't save anything are unfair to users, who often make up the other 10% just to not lose data, so all the validation has done is force the system to lose track of which 10% was made up. Similar issues can happen on the back end - say a data import. I've found it's usually better to try to work properly with invalid data than to try to prevent it from ever happening. –  psr Nov 15 '11 at 18:23
add comment

As I'm sure you already know...

In object-oriented programming, a constructor (sometimes shortened to ctor) in a class is a special type of subroutine called at the creation of an object. It prepares the new object for use, often accepting parameters which the constructor uses to set any member variables required when the object is first created. It is called a constructor because it constructs the values of data members of the class.

Checking validity of the data passed in as c'tor parameters is definitely valid in the constructor - otherwise you're possibly allowing the construction of an invalid object.

However (and this is just my opinion, can't find any good docs on it at this point) - if data validation requires complex operations (such as async operations - perhaps server-based validation if developing a desktop app), then it's better put in an initialization or explicit validation function of some sort and the members set to default values (such as null) in the c'tor.


Also, just as a side note as you included it in your code sample...

Unless you're doing further validation (or other functionality) in AddOrderLine, I'd most likely expose the List<LineItem> as a property rather than have Order act as a facade.

share|improve this answer
add comment

Despite the fact this question is a little stale, I'd like to add something worthwhile:

I'd like to agree with @MichaelBorgwardt and extend by bringing up testability. In "Working Effectively with Legacy Code", Michael Feathers talks a lot about obstacles to testing and one of those obstacles is "difficult to construct" objects. Constructing an invalid object should be possible, and as Fowler suggests, context dependent validity checks should be able to identify those conditions. If you can't figure out how to construct an object in a test harness you're going to have trouble testing your class.

Regarding validity I like to think of control systems. Control systems work by constantly analyzing the state of an output and applying corrective action as the output deviates from the set point, this is called closed loop control. Closed loop control intrinsically expects deviations and acts to correct them and that's how the real world works, which is why all real control systems typically use closed loop controllers.

I think using context dependent validation and easy to construct objects will make your system easier to work with down the road.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.