1

This question already has an answer here:

I've recently read this blog post regarding what a constructor should do and I am also reading Eric Evans' book on Domain Driven Design.

Both the blog post and the book state that a constructor should have a bare minimum amount of logic in it, as to bring the object to a sane default state. But my question is, shouldn't immutable objects like the one below be an exception to this rule?

public class SomeReport
{
    public SomeReport(IReadOnlyList<Order> orders)
    {
        this.Orders = orders;

        this.TotalWithoutTax = orders.Sum(o => o.TotalWithoutTax);
        this.TotalTax = orders.Sum(o => o.Tax);
        this.TotalWithTax = this.TotalWithoutTax + this.TotalTax;

        this.OutStandingOrders = orders.Where(o => o.RespectsSomeComplexBusinessRule()).ToList();
        this.TotalWithoutTax_OutStandingOrders = this.OutStandingOrders.Sum(o => o.TotalWithoutTax);
        this.TotalTax_OutStandingOrders = this.OutStandingOrders.Sum(o => o.Tax);
        this.TotalWithTax_OutStandingOrders = this.TotalWithoutTax_OutStandingOrders + this.TotalTax_OutStandingOrders;
    }

    public IReadOnlyList<Order> Orders { get; }

    public decimal TotalWithoutTax { get; }

    public decimal TotalTax { get; }

    public decimal TotalWithTax { get; }

    public IReadOnlyList<Order> OutStandingOrders { get; }

    public decimal TotalWithoutTax_OutStandingOrders { get; }

    public decimal TotalTax_OutStandingOrders { get; }

    public decimal TotalWithTax_OutStandingOrders { get; }
}

Think of this object as being the container that will be sent to a PDF framework as input for a report for some business analyst (and ignore the fact that there may be some duplicated logic inside. The purpose of this class is to illustrate a complex initialization sequence for an immutable object).

As you can tell, the constructor could contain some complex logic like filtering, sorting and grouping in order to bring the input data into the shape required by the report, which in enterprise reports can mean some serious work.

In my opinion, this is very much in line with what OOP states about how data and behavior should work together inside the same construct to reach the desired goal.
If I were to split this class into a 2 different constructs, one that holds the data and one that assembles it (the factory) the way Eric Evans suggests in his book, I would essentially leave the realm of OOP and venture into the procedural/functional paradigms. Furthermore, I would lose (some of) the benefits of immutability, since from the moment the SomeReport POCO/POJO is initialized to the moment the factory is done initializing it, it is in an invalid state, thus violating the very purpose of a constructor - to have a valid instance of an object right after it has been called.

These being said, am I missing something else or when it comes to immutable objects it is a sane approach to do some heavy-lifting inside the constructor, since its initial state will also be its final state?

P.S: The heavy-lifting should be deterministic and if need be, computed properties can be made lazy.

marked as duplicate by gnat, Doc Brown c# Jun 19 '18 at 12:37

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • I'd actually make sure every one of those properties will be executed for every instance of this object. That's a lot of query and calculation going on, which can make the initialization expensive, depending on the number of orders you are processing. – Berin Loritsch Jun 19 '18 at 12:38
  • 1
    Suggested links look like legit answers to my question. Thanks! This question can be marked as duplicated. – Ciprian Vilcan Jun 19 '18 at 12:51
  • If you are using C# you don't really have to do a lot of complex logic in the constructor. You could always use named constructors, or static methods that do some logic and then dump the output into a separate constructor whose only purpose is to assign data to private fields. – Snoop Jun 19 '18 at 13:26