Using Factory with Strategy design pattern

Cory Gross picture Cory Gross · Nov 17, 2012 · Viewed 11k times · Source

Okay, so I have been given an assignment where I am asked to use both the Strategy and Factory design patterns. Here is the problem:

You are developing an application for a bank to use for handling loans. There is a Loan class with a method capital(). The capital() method contains an ugly if-then-else conditional which checks some of the Loan object instance attributes and uses the correct strategy for the loan type based on the attributes. Here is the psuedo-code for the capital() method:

capital() {
    if (expiry == null && maturity != null) {
        // Find capital for term loan
        return commitment * duration * riskFactor;
    }
    if (expiry != null && maturity == null) {
        if (getUnusedPercentage() != 1.0) {
            // Find capital for revolving loan
            return commitment * unusedPercentage * duration * riskFactor;
        } else {
            // Find capital for complex loan
            return (outstandingRiskAmount * duration * riskFactor) + (unusedRiskAmount * duration * unusedRiskFactor);
        }
    }
}

We would like to introduce the Strategy pattern to this design. Create a Factory that creates the appropriate Strategy object. Make the Factory a Singleton class. Draw a UML diagram and write the cope snippets to replace the capital() method. Remember: the key thing about using a Strategy: the client should provide a context object.

Okay, so I have drawn up a UML diagram. I am pretty solid on my understanding of Singleton so I think I got that down pat. I think I understand Strategy pretty well also. However, I am having trouble convincing myself that the setup I have with the Factory creating the Strategy objects is the best way to go about this. Check out my diagram here. I plan on writing up a client object that creates loans, using the loan as the context object (initializing it with the appropriate strategy through the Loan constructor by creating it with the factory). The capital() method will then just execute whatever strategy it has been configured with. If my understanding is correct, the way I have the factory set up here it is serving to completely decouple the Loan (Context) from the Strategy by adding a layer of indirection.

One thing I am unsure of is how to get the data that is used during the calculation that happened inside the original capital method. For some of the strategies only a few parameters are used (for term loans only commitment, duration, and riskFactor are used, however complex loans use all available attributes of the loan). Should my calculateCapital() method, which is implemented by all the strategies, have all six attributes as parameters?

Is there a better way to use Factory with the Strategy pattern to get a better result? Should I be using AbstractFactory or Factory Method instead?

Answer

David Osborne picture David Osborne · Nov 17, 2012

Here's my interpretation of this question and my answer:

The factory must create the appropriate strategy. It can only do this if knows about properties of the loan. Therefore the factory must be given the loan, via whatever injection method you prefer, and then use the properties of the loan to decide which strategy to give back.

So now you have a strategy that's appropriate for the type of the loan, you must calculate the capital. Again, this relies on properties of the loan. Therefore, the strategy needs the loan. This could be injected via a constructor in the factory or via a parameter of the capital/calculateCapital method.

This keeps it nice and simple, loosely coupled and abstract.

Something like:

ICapitalStrategy s = LoanStrategyFactory.Create(loan);
s.CalculateCapital(loan);