Factory Initializer + Singleton

时间:2010-11-13 18:36:46

标签: c# singleton factory

我为Abstract Factory设计编写了一个非静态Generic类实例化器,并使用Singleton方法确保每个客户端请求只初始化一个实例化实例。

public sealed class FactoryInstantiator<T> where T: class
{
    private static readonly FactoryInstantiator<T> _instance = new Instantiator<T>();
    public static FactoryInstantiator<T> Instance
    {
        get
        {
            _client = HttpContext.Current.Session["ClientCode"].ToString();
            return _instance;
        }
    }

    private static string _client;
    private string _className;
    private string _fullyQualifiedClassName;
    private string _assemblyName;

    private FactoryInstantiator() { }

    public T CreateInstance()
    {
        string fullClassName = typeof(T).ToString();
        string[] splitClassName = fullClassName.Split('.');
        _className = splitClassName[2];
        _assemblyName = splitClassName[0] + "." + _client + "." + splitClassName[1];
        _fullyQualifiedClassName = _assemblyName + "." + _className;

        return (T)Activator.CreateInstance(Type.GetType(_fullyQualifiedClassName + "," + _assemblyName));
    }
}

我抽象了每个客户端的整个命名空间

namespace InventorySuite.Factory.BusinessLogic
{
    // abstract factory
    public abstract class InvoiceFactory
    {
        public abstract void Set() { }
    }
}

namespace InventorySuite.Client1.BusinessLogic
{
    // concrete invoice class for Client1
    public class Invoice : InvoiceFactory
    {
        public override void Set() { }
    }
}

namespace InventorySuite.Client2.BusinessLogic
{
    // concrete invoice class for Client2
    public class Invoice : InvoiceFactory
    {
        public override void Set() { }
    }
}


protected void Page_Load(object sender, EventArgs e)
{       
    InvoiceFactory clientInvoice;

    Session.Add("ClientCode", "Client1");
    clientInvoice = FactoryInstantiator<InvoiceFactory>.Instance.CreateInstance();
    clientInvoice.Set();

    Session["ClientCode"] = "Client2";
    clientInvoice = FactoryInstantiator<InvoiceFactory>.Instance.CreateInstance();
    clientInvoice.Set();

}

它运行良好并已经过测试,但我的问题是它的效率/性能受到影响,因为我在这里使用反射,如果它有多线程问题,那么对于Singleton方法(afaik,单例实例将在所有客户)。我还要感谢任何其他方法。感谢

3 个答案:

答案 0 :(得分:1)

由于您每次都在创建新实例,因此不会出现任何多线程问题。

关于表现。您可以测量创建100个实例的时间:

long ini = Environment.TickCount;
for (int i = 0; i < 100; i++)
{
    Session["ClientCode"] = "Client2";
    clientInvoice = FactoryInstantiator<InvoiceFactory>.Instance.CreateInstance();
    clientInvoice.Set();
}
long timeCreate100Instances = Environment.TickCount - ini;

使用reflection,性能命中在于加载程序集。我认为在你的情况下,你加载的课程是在同一个dll中,你也不会尝试任何性能问题。

在其他情况下,您可以在Assembly方法的Hastable/Dictionary中缓存CreateInstance()个主题。

答案 1 :(得分:0)

使用Richard和Daniel的建议,我能够使用缓存降低反射的性能。因此,我得出结论,Reflection确实存在巨大的性能问题。

  public T CreateInstance()
    {
        string fullClassName = typeof(T).ToString();
        string[] splitClassName = fullClassName.Split('.');
        _className = splitClassName[2];
        _assemblyName = splitClassName[0] + "." + _client + "." + splitClassName[1];
        _fullyQualifiedClassName = _assemblyName + "." + _className;

        // use caching
        T obj;
        if (HttpContext.Current.Cache[_fullyQualifiedClassName] == null)
        {
            obj = (T)Activator.CreateInstance(Type.GetType(_fullyQualifiedClassName + "," + _assemblyName));
            HttpContext.Current.Cache.Insert(_fullyQualifiedClassName, obj, null, DateTime.Now.AddMinutes(1), TimeSpan.Zero);
        }
        else
        {
            obj = (T)HttpContext.Current.Cache[_fullyQualifiedClassName];
        }

        return obj;
    }


protected void Page_Load(object sender, EventArgs e)
{
    InvoiceFactory inv;

    Stopwatch globalTimer = Stopwatch.StartNew();

    //normal instantiation
    globalTimer = Stopwatch.StartNew();
    for (int x = 0; x <= 10000; x++)
        inv = new InventorySuit.Client1.BusinessLogic.Invoice;
    globalTimer.Stop();
    Response.Write(globalTimer.ElapsedMilliseconds + "<BR>");
    //result 0ms


    // using singleton factory w/o caching
    globalTimer = Stopwatch.StartNew();
    for (int x = 0; x <= 10000; x++)
        inv = new FactoryInstantiator<InvoiceFactory>().CreateInstance();
    globalTimer.Stop();
    Response.Write(globalTimer.ElapsedMilliseconds + "<BR>");
    //result 129ms

    // using singleton factory w/ caching
    for (int x = 0; x <= 10000; x++)
        inv = FactoryInstantiator<InvoiceFactory>.Instance.CreateInstance();
    globalTimer.Stop();
    Response.Write(globalTimer.ElapsedMilliseconds + "<BR>");
    //result 21ms



}

答案 2 :(得分:0)

在会话状态中加载程序集以解决多线程问题。

   public T CreateInstance()
    {
        string fullClassName = typeof(T).ToString();
        string[] splitClassName = fullClassName.Split('.');
        _className = splitClassName[2];
        _assemblyName = splitClassName[0] + "." + _client + "." + splitClassName[1];
        _fullyQualifiedClassName = _assemblyName + "." + _className;


        T obj;
        var assemblies = HttpContext.Current.Session["ASSEMBLIES"] as Dictionary<string, T>;

        if (assemblies == null)
        {
            assemblies = new Dictionary<string, T>();
            assemblies.Add(_fullyQualifiedClassName, null);
            HttpContext.Current.Session.Add("ASSEMBLIES", assemblies);
        }

        obj = assemblies[_fullyQualifiedClassName] as T;

        if (obj == null)
        {
            obj = (T)Activator.CreateInstance(Type.GetType(_fullyQualifiedClassName + "," + _assemblyName));
            assemblies[_fullyQualifiedClassName] = obj;
        }



        return obj;
    }