Anti-Pattern 3: Overloaded Constructor

by geoffrey 10. May 2010 19:06

In the previous example the “Invoice” object is responsible to retrieve all the values needed to calculate the balance and it also contains the business logic that performs the calculation. This violates the SRP (Single Responsibility Principle). Because of this flaw when we test the calculation of the Balance we need to inject a test double so that the invoice can retrieve values. Why should we need to pass a Service when the only thing our Invoice should be responsible for is the calculation of the Balance?

In the code example here below we specialized the Invoice class. Only what is directly needed is passed in: the input data to calculate the balance. To adhere to the SRP we extract the logic that retrieves the data from our DataLayer out of the Invoice class and create a Repository class (see Repository pattern). We don’t need any mock object anymore what enhance the readability and robustness of our test. By adhering to the SRP we improve our design and enable for better testability.

SUT

public class Invoice
{
    private int _balance;
 
    public Invoice(MeteringValues[] dailyValues, int offPeakPrice, int peakPrice, int advances)
    {
 
        int peakConsumption = CalculatePeakConsumtion(dailyValues);
        int offPeakConsumtion = CalculateOffPeakConsumtion(dailyValues);
 
        _balance = CalculateBalance(
                            peakConsumption, 
                            peakPrice, 
                            offPeakConsumtion, 
                            offPeakPrice, 
                            advances
                            );
    }
 
...
}
 
public class InvoiceRepository
{
    private IDataLayer _db;
    public InvoiceRepository(IDataLayer db)
    {
        _db = db;
    }
    public Invoice GetInvoice(int clientID)
    {
        MeteringValues[] dailyValues = _db.GetMeteringValues(clientID);
        int offPeakPrice = _db.GetOffPeakPrice();
        int peakPrice = _db.GetPeakPrice();
        int advances = _db.GetAdvances(clientID);
 
        return new Invoice(dailyValues, offPeakPrice, peakPrice, advances);
    }
}

 

Tags:

Unit Testing

blog comments powered by Disqus

About the author

Geoffrey Vandiest

contact

View Geoffrey Vandiest's profile on LinkedIn

Follow me on twitter

Geoffrey Vandiest is a technical fellow who learned the art of programming at the age of 10 on a Philips MSX computer. He's skilled in the architecture and development on the Microsoft platform and started experimenting with the Microsoft .Net framework as from the Beta 1 in 2001. Since nearly a decade Geoffrey coaches development teams and base his management style on Agile principles.

 

Month List