强制使用工厂对象来实例化类

时间:2013-05-17 00:47:29

标签: c# factory-pattern

我有一个特殊情况,一个对象需要在每个线程的基础上成为一个单例。所以我想使用Factory类的静态工厂方法来实例化这些实例。为了确保使用工厂类(因为它为每个线程缓存),需要保护构造函数。

所以,假设我有一个这样的课程。

public class XXXX : Model {
    protected XXXX() {
    }
}

我想使用这样的工厂类。

public class Factory {

     private static Dictionary<int,Model> _singletons;

     public static T Instance() where T : Model {
          int thread = Thread.CurrentThread.ManagedThreadId;
          if(!_singletons.ContainsKey(thread))
          {
              _singletons[thread] = new T();
          }
          return (T)_singletons[thread];
     }
}

然后我可以像这样获得对每个单例的引用,并且每个线程的引用都是唯一的。

XXXX m = Factory.Instance<XXXX>();

我该怎么做才能让Factory类有权创建实例。一个问题是类将在将在运行时加载的其他DLL中定义。我只能知道它们来自Model并且有protected/private个构造函数。

3 个答案:

答案 0 :(得分:4)

一些选项:

  • 反射
  • 注册使用工厂类创建类的委托
  • 将您的DI容器配置为按照您所需的类型
  • 的方式运行

委托方法的近似代码:

public class Factory {
   private static Dictionary<Type, Func<Model>> creators;
   public void AddCreator<T>(Func<T> creator) where T:Model
   {
      creators.Add(typeof(T), ()=> creator());
   }

   public static T Instance() where T : Model 
   {
       return (T)(creators[typeof(T)] ());
   }
}

答案 1 :(得分:1)

您的XXXX类需要一个公共构造函数,或者它们需要一个内部构造函数,并且您将包含工厂的程序集定义为包含XXXX类的程序集中的友元程序集。

请参阅http://msdn.microsoft.com/en-us/library/0tke9fxk%28v=vs.80%29.aspx

答案 2 :(得分:0)

如果你想要实现的是:这个类和它的任何衍生物必须使用类工厂方法,无论谁实现派生类(lib使用者,在其他程序集中等)。

在基类中,声明一个私有的无arg构造函数和一个带有私有“key”arg的构造函数。然后声明一个模板化方法,该方法将类型作为参数并使用反射来实现类。

为什么魔术钥匙?因为您需要至少一个公共或受保护的构造函数才能专门化基类,所以一旦您这样做,您的子级别选择强制执行或不工厂使用。

缺点是使用Invoke。减慢了一些事情。在最终这是一个问题,你总是可以在运行时调用编译为特定类型喷出适当的委托并存储它们。所以你慢慢为每种类型构建一个构造函数委托的字典。但超出了这个问题的范围。

public class BaseClass 
{
    private static string factoryKey = "sdfdsfdsfdsfhdfdsgdfsgd";
    private BaseClass()
    {
        throw new ArgumentException("error");
    }

    protected BaseClass( string key)
    {
        if( key != factoryKey)
            throw new ArgumentException("error");
    }

    public static T CreateInstance<T>() where T : BaseClass
    {
        Type type = typeof(T);
        var ctor = type.GetConstructor(new[] { typeof(string) });
        var instance = ctor.Invoke(new object[] { factoryKey }) as T;

        return instance;
    }

}