Reputation: 401
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?
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
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
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
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
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
Reputation: 561
You would do
strategy = (IStrategy)Activator.CreateInstance(Type.GetType(strategyName));
Upvotes: 0