0

I have the "feeling" that my design to invoke a method to load data inside the constructor is not right.

I try to write a class that provides the basic logic to perform a calculation (discount, tax, total-amount etc.) for invoices-, orders- or quotes-record. In most cases are the same set of attributes needed (e.g. the attribute "quantity" is present in all entities/tables).

In my current design is use this base class (note this is not the real code, i am at home and do not have access to the code-base, so typos are likely):

public abstract class HeadCalculationEngineBase
{
    protected readonly IOrganisationService orgService;
    protected decimal pricePerUnit;
    protected decimal quantity;

    public HeadCalculationEngineBae(Guid entityid, IOrganisationService service)
    {
        this.orgService = service;
        this.populate(this.loadEntityData(id));
    }

    public virtual Entity loadEntityData(Guid id)
    {
        var columns = new ColumnSet("pricePerUnit", "quantity");

        return this.orgService.Retrieve(id, columns);
    }

    protected virtual populate(Entity data)
    {
        this.pricePerUnit = data["pricePerUnit"];
        this.quantity = data["quantity"];
    }
}

This design gives me the option to override the virtual member and load additional attributes for my implementation for the invoice entity:

public class HeadCalculationInvoiceEngine : HeadCalculationEngineBase
{
    protected decimal discount;

    public HeadCalculationInvoiceEngine(Guid entityid, IOrganisationService service)
        :base(entityid, service)
    { }

    public override Entity loadEntityData(Guid id)
    {
        var columns = new ColumnSet("pricePerUnit", "quantity", "discount");

        return this.orgService.Retrieve(id, columns);
    }

    protected override populate(Entity data)
    {
        this.pricePerUnit = data["pricePerUnit"];
        this.quantity = data["quantity"];
        this.discount = data["discount"];
    }
} 

So my problem comes down to the question: Should I load data inside the constructor?

thuld
  • 680
  • 3
  • 10
  • 29

1 Answers1

3

Better to keep constructors lightweight and avoid long and especially remote calls.

  • Failures in constructor are harder to reason about than exceptions thrown by methods.
  • it is harder to mock such functionality for unit test (you can't extract constructor to interface for example)
  • constructors can't be asynchronous - so when you try to switch to modern asynchronous APIs to access remote resources you'll have to significantly modify way you construct objects.
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179