我为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,单例实例将在所有客户)。我还要感谢任何其他方法。感谢
答案 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;
}