Plantain Yao
Plantain Yao

Reputation: 401

How can I implement the creation / factory concern of the Strategy pattern?

  1. Question

I have a full name of a type, for example "StrategyA",and I want to get new Strategy(value) that assigned to its interface "IStrategy", how to get it?

  1. What I have tries

I have tried this:

IStrategy strategy;
if (strategyName == "StrategyA")
{
    strategy = new StrategyA(value);
}
else if(strategyName == "StrategyB")
{
    strategy = new StrategyB(date);
}
...

but when I create a new strategy , I have to add another branch to the code, and I think it is a bad code style. Is there any better way to solve this problem?

Upvotes: 2

Views: 204

Answers (5)

Sam
Sam

Reputation: 2917

Try Constructor Injection (part of Dependency Injection)

E.g.

public class MyStrategy
{
    IStrategy strategy;

    public MyStrategy(IStrategy concreteImplementation)
    {
        this.strategy = concreteImplementation;
    }
}

In this way you can pass any object that implements IStrategy interface. So you could eliminate the If...else conditions in your constructor. The usage of this is as follows.

StrategyA strategyA = new StrategyA(value);
MyStrategy myStrategyA = new MyStrategy(strategyA);

StrategyB strategyB = new StrategyB(date);
MyStrategy myStrategyB = new MyStrategy(strategyB);

StrategyC strategyC = new StrategyC(someValue);
MyStrategy myStrategyC = new MyStrategy(strategyC);

Hope this helped!

Upvotes: 0

Michael Petito
Michael Petito

Reputation: 13161

Here are a few options, in no particular order:

(A) If your strategy name is a full CLR type name (or a full type name may be determined by convention), and each strategy has common constructor parameters, you can find the type using reflection and create an instance.

Type strategyType = Type.GetType(strategyName)
IStrategy instance = (IStrategy)Activator.CreateInstance(strategyType, paramArray);

Be aware that you should not use this approach if you cannot trust the strategyName input, otherwise you may be creating instances of unexpected types.

(B) You could create a mapping from strategy name to factory delegate using a dictionary. This approach may be useful if various constructors are used, or if factories come and go.

Dictionary<string, Func<IStrategy>> factories = new Dictionary<string, Func<IStrategy>>();
//register various factories
factories.Add("StrategyA", () => new StrategyA(value));
factories.Add("StrategyB", () => new StrategyB(date));

Func<IStrategy> factory;
if(factories.TryGetValue(strategyName, out factory))
{
    IStrategy instance = factory();
}

(C) You could rely on any number of IoC containers such as Autofac, and ask for the corresponding IStrategy implementation.

(D) Another related pattern that is sometimes used relies on implementations of IStrategy to check applicability and returning the first one which is applicable. This can be useful when the caller doesn't know which strategy to pick.

List<IStrategy> strategies = new List<IStrategy>();
//register strategies (highest priority first)
strategies.Add(new StrategyA(value));
strategies.Add(new StrategyB(value));
//alternatively, you might resolve IEnumerable<IStrategy> from your IoC container

foreach(IStrategy strategy in strategies)
{
    if(strategy.IsApplicable(someInput)) return strategy;
}

Upvotes: 4

Mahesh Malpani
Mahesh Malpani

Reputation: 1999

There are various ways of doing it.

1) Simple switch case, if your conditions are less

2) IOC containers. http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx or Unity container provided by microsoft http://msdn.microsoft.com/en-us/library/ff649614.aspx

3) Activator.CreateInstance(type);

4) You can customize your own using factory design pattern

Upvotes: 0

wraith
wraith

Reputation: 351

Why don't you use Reflection. Some thing like :

 Type type = Type.GetType(strategyName, true);
 // create an instance of that type
 object instance = Activator.CreateInstance(type);

Upvotes: 0

user1325394
user1325394

Reputation: 561

You would do

strategy = (IStrategy)Activator.CreateInstance(Type.GetType(strategyName));

Upvotes: 0

Related Questions