如何实现策略模式的创建/工厂关注?

时间:2014-12-11 03:50:37

标签: c# .net strategy-pattern

  1. 问题
  2. 我有一个类型的全名,例如“StrategyA”,我想获得分配给其“IStrategy”界面的新策略(值),如何获得它?

    1. 我尝试了什么
    2. 我试过这个:

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

      但是当我创建一个新策略时,我必须在代码中添加另一个分支,我认为这是一个糟糕的代码风格。 有没有更好的方法来解决这个问题?

5 个答案:

答案 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);

希望这有帮助!