2010-11-13 3 views
0

Я написал нестатический универсальный экземпляр класса для моего абстрактного дизайна Factory и использовал подход Singleton, чтобы убедиться, что только один экземпляр экземпляра будет инициализирован для каждого запроса клиента.Factory Initializer + 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, экземпляр singleton будет использоваться для всех клиентов). Я также буду признателен за любой другой подход. спасибо

+3

Похоже на решение проблемы, для меня. – Mark

+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 obejcts в Hastable/Dictionary в вашем методе CreateInstance().

0

Используя рекомендации Ричарда и Дэниела, я смог уменьшить ударный эффект отражения с помощью кеширования. Поэтому я полагаю, что 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 



} 
+0

Я добавил 1 цифру на это для цикла ctr, и результат был указан. – CSharpNoob

+1

Будьте осторожны, потому что теперь вы используете общий экземпляр, теперь у вас могут быть проблемы с несколькими потоками. Теперь ваши экземпляры должны быть потокобезопасными. –

+0

вы считаете, что отражение имеет огромные проблемы с производительностью? Я бы сделал вывод, что хотя обычное отражение в 6 раз медленнее, чем ваша измененная версия, если вы можете создать 10000 предметов в 129 мс, это достаточно быстро для всех. –

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; 
    } 
Смежные вопросы