views:

112

answers:

2

Consider an application that generates production plans (simplified code sample below) . There's a big list of products and we call product.GetProductionTime() many times while doing complex calculations in the production plan. We need product.GetProductionTime() to behave differently based on the planning algorithm we are using or the step of the algorithm that we are in. The conditionals in the GetProductionTime() is ugly and adding another algorithm is not easy.

I am thinking about strategy pattern. Is this a good place to implement it? If yes, how would you implement it? If no, what can I do?

public class ProductionPlanningProblem
{
    public List<Product> Products;
    public void GenerateFastProdPlan()
    {
        foreach (Product product in Products)
        {
            //do lots of calculations 
            product.GetProductionTime(PlanType.Fast);
            //do lots of calculations 
        }
    }
    public void GenerateSlowProdPlan()
    {
        foreach (Product product in Products)
        {
            //do lots of calculations 
            product.GetProductionTime(PlanType.Slow);
            //do lots of calculations 
        }
    }
}
public class Product
{
    public int GetProductionTime(Plantype plantype)
    {
        if(plantype.Fast)
            return CalculationFast();
        if (plantype.Slow && SomeOtherConditionsHold)
            return CalculationSlow();
        return CalculationFast();
    }

    private int CalculationFast()
    {
        //do fast calculation depending on many fields of product
        return result;
    }
    private int CalculationSlow()
    {
        //do slow but more accurate calculations depending on many fields of product            
        return result;
    }
}
+1  A: 

Basically, you want to rip out that big if/switch statement in GetProductionTime and turn each case into various smaller, sensible classes. Each class will be a different strategy that calls CalculationFast or CalculationSlow using different conditions.

For instance, if your language supports inner classes (Java) and Plantype only needs to inspect the state of Product to decide between fast & slow:

public interface Plantype
{
    public int Calc();
}

public class Product
{
    public class Plantype_one implements Plantype
    {
        public int Calc()
        {
            if (<some simple condition holds for Product instance>) {
                 return CalculationFast();
            } else {
                 return CalculationSlow();
            }
        }
    }
    public class Plantype_two implements Plantype
    {
        public int Calc()
        {
            if (< some different & simple condition holds for Product instance >) {
                 return CalculationFast();
            } else {
                 return CalculationSlow();
            }
        }
    }

    // etc.

    public int GetProductionTime(Plantype plantype)
    {
        return plantype.Calc();
    }

    private int CalculationFast()
    {
        //do fast calculation depending on many fields of product
        return result;
    }
    private int CalculationSlow()
    {
        //do slow but more accurate calculations depending on many fields of product            
        return result;
    }
}

Basically, your algorithm can pick and choose what sort of Plantype makes sense at a given point and pass it along into GetProductionTime.

The inner class approach may be totally wrong, depending WHAT the Plantype class needs to inspect but you get the picture.

hythlodayr
A: 

It is possible to do it with strategy pattern. I'd suggest you the following implementation: Create an interface in Product class that will alow to calculate the production time. Then implement a strategy class ProdTimeCalculationStrategyBase that will have virtual GetProductTime method and inherit all other strategy classes from it. Inside every strategy you'll be able to implement it`s own calculation method.

After that implement a special factory where your switch will move. This factory will create an instance of a strategy calculation class based on the what product you`ll provide to it.

After that your code will act like this: When product is asked to calculate ProductionTime it will provide all details to factory to create a special strategy for calculations. Factory will return the object that is capable of calculating it in the right way. The result returned from strategy will be given to product and it will return it to caller.

Yaroslav Yakovlev