In Refactoring Tip #1 – Null Object Pattern, we used the Null Object pattern to refactor the legacy code, and to make it easier to understand and maintain. There were  further refactoring opportunities. Looked at the following code:

private static LoanApplicantResponse ProcessBusinessLogic1(
    ApplicantInfo applicant, LoanApplicantResponse response)
{
    // process information
    if (condition1 == false)
    {
        // log the error           
        return response;
    }

    return new NullLoanApplicantResponse(); // <-- refactoring this line
}

// .....

private static LoanApplicantResponse ProcessBusinessLogicN(
    ApplicantInfo applicant, LoanApplicantResponse response)
{
    // process information
    if (conditionN == false)
    {
        // log the error           
        return response;
    }

    return new NullLoanApplicantResponse(); // <-- refactoring this line
}

Pay attention to this line of code:

    return new NullLoanApplicantResponse();

This one line of code was at the end of every ProcessBusinessLogicN method. We can imagine there were too many instance of NullLoanApplicantResponse created and disposed during these method calls in a high-volume system wasting valuable resources.

Here came Singleton Pattern for the rescue. However, Singleton is NOT the silver bullet. There are a lot of discussion about Singleton Pattern on the Internet. The main disadvantages are:

  1. tight coupling among collaborating classes
  2. difficult to implement in some scenarios
  3. difficult to test, sometimes regarded as anti-pattern
  4. violate SRP
  5. object lifetime should be handled by a IOC container

However, in the end we decided to use Singleton in our case due to:

  1. well-known pattern, and easy to understand
  2. no apparent side effects since we only used the instance and ‘IsNull’ method
  3. time constraint. We refactored as we go.
  4. difficulty to integrate IOC with legacy code

In c# 4.0, a new feature Lazy<T> was introduced. We are going to take advantage of that. Here is our new NullLoanApplicantResponse class.

public sealed class NullLoanApplicantResponse
{
    private static readonly Lazy<NullLoanApplicantResponse> lazy =
        new Lazy<NullLoanApplicantResponse>(() => new NullLoanApplicantResponse());
 
    public static NullLoanApplicantResponse Instance { get { return lazy.Value; } }
        
    private NullLoanApplicantResponse()
    {
    }
}

So the method ProcessBusinessLogicN became:

private static LoanApplicantResponse ProcessBusinessLogicN(
    ApplicantInfo applicant, LoanApplicantResponse response)
{
    // process information
    if (conditionN == false)
    {
        // log the error           
        return response;
    }

    return NullLoanApplicantResponse.Instance; // <-- After refactoring 
}

In summary, after second round of refactoring using Singleton Pattern, the code was  easy to understand and maintain. In addition, there were performance gains along with small memory footprints.

 

Advertisements