我有一个类型的全名,例如“StrategyA”,我想获得分配给其“IStrategy”界面的新策略(值),如何获得它?
我试过这个:
IStrategy strategy;
if (strategyName == "StrategyA")
{
strategy = new StrategyA(value);
}
else if(strategyName == "StrategyB")
{
strategy = new StrategyB(date);
}
...
但是当我创建一个新策略时,我必须在代码中添加另一个分支,我认为这是一个糟糕的代码风格。 有没有更好的方法来解决这个问题?
答案 0 :(得分:4)
以下是几个选项,没有特别的顺序:
(A)如果您的策略名称是完整的CLR类型名称(或者可以通过约定确定完整类型名称),并且每个策略都有常见的构造函数参数,您可以使用反射找到类型并创建实例。 / p>
Type strategyType = Type.GetType(strategyName)
IStrategy instance = (IStrategy)Activator.CreateInstance(strategyType, paramArray);
请注意,如果您不能信任strategyName输入,则不应使用此方法,否则您可能会创建意外类型的实例。
(B)您可以使用字典创建从策略名称到工厂委托的映射。如果使用各种构造函数,或者工厂来来去去,这种方法可能很有用。
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)您可以依赖任意数量的IoC容器,例如Autofac和ask for the corresponding IStrategy implementation。
(D)有时使用的另一种相关模式依赖于IStrategy
的实现来检查适用性并返回适用的第一个模式。当调用者不知道要选择哪种策略时,这可能很有用。
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;
}
答案 1 :(得分:0)
你会做
strategy = (IStrategy)Activator.CreateInstance(Type.GetType(strategyName));
答案 2 :(得分:0)
为什么不使用Reflection。 有点像:
Type type = Type.GetType(strategyName, true);
// create an instance of that type
object instance = Activator.CreateInstance(type);
答案 3 :(得分:0)
有各种方法可以做到。
1)简单的开关盒,如果条件较差
2)IOC容器。由http://www.hanselman.com/blog/ListOfNETDependencyInjectionContainersIOC.aspx
提供的http://msdn.microsoft.com/en-us/library/ff649614.aspx或Unity容器3)Activator.CreateInstance(type);
4)您可以使用工厂设计模式自定义您自己的模式
答案 4 :(得分:0)
尝试构造函数注入(依赖注入的一部分)
E.g。
public class MyStrategy
{
IStrategy strategy;
public MyStrategy(IStrategy concreteImplementation)
{
this.strategy = concreteImplementation;
}
}
通过这种方式,您可以传递任何实现IStrategy
接口的对象。因此,您可以消除构造函数中的If...else
条件。使用方法如下:
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);
希望这有帮助!