botenvouwer
botenvouwer

Reputation: 4432

How to implement a factory that automatically finds a strategy

I've asked myself this question and I'm still not done thinking about this.

What I am thinking about

When you have a strategy pattern, a lot of implementations also use a factory pattern to retrieve a specific strategy. Most factory examples on the internet make use of a switch or if statement. This works perfectly when you do not often change or add strategies. But what if the factory is used to dynamically find a strategy and the strategies are changed and added often. Then this is a full time job for the programmer. Now I have a situation where I just want to add a new strategy without having to change the factory. In other words how do you implement the factory pattern so it dynamically searches for a strategy. And how can I list all available strategies.

The problem

When I look for this on the internet I can't find a good proper solution. I am thinking about using a reflection library to do this but it is not recommended to use reflection everywhere I look. So how to implement a dynamic factory. Or is there an other pattern for this purpose?

Example

The strategies: enter image description here

The factory:

public enum StrategyName { ImplementedStrategy1, ImplementedStrategy2, ImplementedStrategy3 };

public class StrategyFactory
{
    public static Sniffer getInstance(StrategyName choice) {

        Strategy strategy = null;

        switch (choice) {
            case StrategyName.ImplementedStrategy1:
                strategy = new ImplementedStrategy1();
                break;
            case StrategyName.ImplementedStrategy2:
                strategy = new ImplementedStrategy2();
                break;
            case StrategyName.ImplementedStrategy3:
                strategy = new ImplementedStrategy3();
                break;
        }

        return strategy;
    }
}

Now how can I make this dynamic? Or why shouldn't I?

Upvotes: 5

Views: 747

Answers (3)

Russ
Russ

Reputation: 124

Not sure if you still need this but it can be achieved in Java as below.

public interface Strategy {
    boolean isGoodMatch(StrategyName strategyName);
}

public class ImplementedStrategy1 implements Strategy {
    @Override
    public boolean isGoodMatch(StrategyName strategyName) {        
        return strategyName == StrategyName.ImplementedStrategy1;
    }
}

public class ImplementedStrategy2 implements Strategy {
    @Override
    public boolean isGoodMatch(StrategyName strategyName) {        
        return strategyName == StrategyName.ImplementedStrategy2;
    }
}

public class ImplementedStrategy3 implements Strategy {
    @Override
    public boolean isGoodMatch(StrategyName strategyName) {        
        return strategyName == StrategyName.ImplementedStrategy3;
    }
}

public class StrategyFactory {

    private List<Strategy> strategies;

    public StrategyFactory(List<Strategy> strategies){
        this.strategies = strategies;
    }

    public Strategy getInstance(StrategyName choice){

        Strategy strategyChoice = null;

        for (Strategy strategy: this.strategies){
            if(strategy.isGoodMatch(choice))
                strategyChoice = strategy;
        }        

        return strategyChoice;
    }
}

If you wanted you could use streams in the getInstance method.

public Strategy getInstance(StrategyName choice){

    return strategies
            .stream()
            .filter(x -> x.isGoodMatch(choice))
            .findFirst()
            .get();
}

You can provide the list to the factory by using a DI container as mentioned above. If you are using something like Spring you could use @Autowire annotation.

http://www.baeldung.com/spring-autowire

Upvotes: 1

Lidaranis
Lidaranis

Reputation: 785

I am not sure if this will help but here is what i am thinking. You have

public class ImplementedStrategy1 : Strategy
{

}

public class ImplementedStrategy2 : Strategy
{

}

etc..

Then you make an attribute class [StrategyName(StrategyName.EnumValue)]. More details here https://msdn.microsoft.com/en-us/library/aa288454(v=vs.71).aspx

So, now we get

[StrategyName(StrategyName.EnumValue1)].
public class ImplementedStrategy1 : Strategy
{

}

[StrategyName(StrategyName.EnumValue2)].
public class ImplementedStrategy2 : Strategy
{

}

Then, in public static Sniffer getInstance(StrategyName choice) instead of the switch,using reflection, you get all the types that inherit from Strategy and check if the choice parameter matches the custom attribute value.

Now you just need to create a new instance for that type.

When this is done and you wish to add a new strategy, you just have to create the new class with the attribute and add a new value to the enum.

Let me know if you need any help with the implementation.

Upvotes: 1

GWLlosa
GWLlosa

Reputation: 24413

Have your ImplementedStrategy contract include a IsGoodMatch(params) method. Then you just iterate over your collection of strategies, calling IsGoodMatch on each one until you get one (or many) results, and then you use that strategy(ies).

Upvotes: 2

Related Questions