2016-09-21 8 views
5

के विभिन्न वस्तुओं को बनाने के मैं 1 इंटरफेस है:फैक्टरी एक ही इंटरफ़ेस

public interface ISummary 
{ 
    int EventId {get; set;} 
} 

और कई ठोस वर्ग है कि इस इंटरफ़ेस को लागू:

public class EmployeeSummary : ISummary 
{ 
    public int EventId {get; set;}, 
    public int TotalUniqueCount {get; set;} 
    public int Location {get; set;} 
} 

public class CarSummary : ISummary 
{ 
    public int EventId {get; set;} 
    public int TotalMiles {get; set;} 
    public int TotalHours {get; set;} 
} 

आदि ....

केवल साझा संपत्ति EventId है। क्या 1 फैक्टरी विधि है जो इन सभी सारांश वस्तुओं को बनाता है? मुझे 1 एंट्री पॉइंट चाहिए जो तय करता है कि कौन सी ऑब्जेक्ट्स बनाना है।

तो कुछ की तरह:

public ISummary CreateSummary(ConcreteObjectType with properties) 
{ 
if EmployeeSummary 
--Call this method to create and return EmployeeSummary 

if CarSummary 
--Call this method create and return CarSummary 
} 

मैं अन्य वर्गों के भीतर सभी कॉल नहीं बल्कि खुद वस्तुओं बनाने की तुलना में इस विधि कॉल करना चाहते हैं।

जिस भाग के साथ मैं संघर्ष कर रहा हूं वह है कि मैं इस CreateSummary विधि को ऑब्जेक्ट्स को असाइन करने के लिए गुणों को कैसे पास करूं क्योंकि ऑब्जेक्ट्स पर सभी गुण अलग होंगे?

मैं इस बिंदु पर वस्तुओं को बदलने के लिए खुला हूं अगर बेहतर डिजाइन पैटर्न है तो मुझे यहां उपयोग करना चाहिए।

public class SummaryFactory 
{   
    // new instance with values assigned by action delegate or default 
    public T Create<T>(Action<T> action = null) where T : ISummary, new() 
    { 
     var result = new T(); 

     action?.Invoke(result); 

     return result; 
    } 

    // with object to assign value from (map) 
    public T Create<T>(object map) where T : ISummary, new() 
    { 
     var result = new T(); 
     PropertyInfo[] props = map.GetType().GetProperties(); 
     PropertyInfo[] tProps = typeof(T).GetProperties(); 

     foreach (var prop in props) 
     { 
      var upperPropName = prop.Name.ToUpper(); 
      var foundProperty = tProps.FirstOrDefault(p => p.Name.ToUpper() == upperPropName); 

      foundProperty?.SetValue(result, prop.GetValue(map)); 
     } 

     return result; 
    } 

    // new instance without generic parameters 
    public object Create(Type type) 
    { 
     var result = Activator.CreateInstance(type); 

     // add all logic that you need 

     return result; 
    } 
} 

और अब आप इस कारखाने का उपयोग कर सकते हैं::

+1

आप गुण आप चाहते हैं – Nkosi

उत्तर

9

ठीक है, कि वास्तव में क्यों Factory Method पैटर्न मौजूद है

var factory = new SummaryFactory(); 
var carSummary = factory.Create<CarSummary>(); 
var carSummary2 = factory.Create<CarSummary>(car => { car.TotalMiles = 50; }); 
var carSummary3 = factory.Create<CarSummary>(new { TotalMiles = 50 }); 
var employeeSummary = factory.Create(typeof(EmployeeSummary)); 
+0

आप एक वैकल्पिक पैरामीटर का उपयोग करने के लिए और भी कार्रवाई – Nkosi

+0

@Nkosi अच्छा सुझाव पर अशक्त के लिए जाँच पहले दो तरीकों विलय कर सकते हैं भरने के लिए एक कार्रवाई प्रतिनिधि के साथ एक सामान्य कारखाने विधि, धन्यवाद आप – Fabjan

+0

यह ध्यान दिया जाना चाहिए कि सामान्य तरीकों एक 'नई()' बाधा के साथ कारखाने के तरीके नहीं हैं। एकमात्र चीज ऐसी विधि लौट सकती है जो आपके द्वारा पारित * सटीक * ठोस प्रकार का एक उदाहरण है, जो पैरामीटर रहित कन्स्ट्रक्टर वाले प्रकार तक सीमित है। ओओपी सिद्धांतों (जैसे ढीले युग्मन) के संदर्भ में आप बिल्कुल कुछ हासिल नहीं करते हैं। – Groo

1

वस्तुओं के लिए निर्माताओं के आधार पर, आप ऐसा कर सकता है:

public interface ISummary 
{ } 

public class Bar : ISummary 
{ } 

public class SummaryFactory 
{ 
     public static TSummary CreateSummary<TSummary>() 
      where TSummary : new() 
    { 
     return new TSummary(); 
    } 
} 

public class Foo 
{ 
    public void AMethod() 
    { 
     var bar = SummaryFactory.CreateSummary<Bar>(); 
    } 
} 

लेकिन मुझे नहीं पता कि यह वास्तव में आपको क्या खरीद देगा जब तक कि निर्माता खाली था।

अपने वस्तुओं निर्माता मानकों की क्या ज़रूरत है, तो आप उन्हें बजाय कारखाने पैटर्न के कुछ इस तरह बनाने के लिए, रणनीति पैटर्न का उपयोग कर सकते हैं: एक new() बाधा के साथ

public interface ISummary 
{ } 

public class CarSummary : ISummary 
{ 

    public CarSummary(int someParam) 
    { 

    } 
} 

public interface ISummaryStrategy 
{ 
    /// <summary> 
    /// 
    /// </summary> 
    /// <returns></returns> 
    ISummary Create(); 
} 

public class CarSummaryStrategy 
    : ISummaryStrategy 
{ 
    public ISummary Create() 
    { 
     return new CarSummary(42); //The Answer to the Ultimate Question of Life, the Universe, and Everything 
    } 
} 



public class Foo 
{ 
    private Dictionary< Type, ISummaryStrategy > _summaryStrategies; 
    public Foo() 
    { 
     this._summaryStrategies = new Dictionary< Type, ISummaryStrategy > 
     { 
      {typeof(CarSummary), new CarSummaryStrategy()} 
     }; 

    } 
    public void UseSummaries(Type summary) 
    { 
     var summaryImpl = this._summaryStrategies[summary].Create(); 
     // use the summary 
    } 
} 
1

जेनेरिक्स केवल तंग युग्मन कर रहे हैं। यदि आपको पहले से ही पता होना चाहिए कि जेनेरिक पैरामीटर T के रूप में किस प्रकार को पास करना है, और आप जानते हैं कि विधि क्या बदलेगी, तो इसका उपयोग करने में क्या बिंदु है?

// This is a *helper method* which will create a car summary. 
// No abstraction, no polymorphism, just a template helper method. 
var summary = CreateSummary<CarSummary>(carData); 

आप एक सार कारखाने की जरूरत है, तो इसका मतलब है आपके बुला विधि केवल वापसी इंटरफ़ेस जानता है, और यह कारखाने जो वास्तविक क्रियान्वयन पर फैसला करने के लिए माना जाता है है।

आपके मामले में, (मुझे विश्वास है) आपके पास कई प्रकार के डेटा वर्ग हैं, और आप प्रत्येक प्रकार के लिए उचित सारांश बनाने की विधि चाहते हैं। अर्थात। कुछ ऐसा:

class EmployeesData : IEmployeesData 
{ ... } 

class CarsData : ICarsData 
{ ... } 

// at this point we don't know what `data` actually is 
IData data = GetDataFromSomewhere(); 

// so we cannot pass the concrete generic parameter here 
ISummary summary = GetSummary(data); 

फिर आपको जो कुछ चाहिए वह एक रणनीति है जो रनटाइम पर सही कार्यान्वयन का चयन करेगी।विभिन्न इनपुट प्रकार के लिए रणनीतियाँ कार्यक्रम स्टार्टअप पर पंजीकृत किया जाना चाहिए (कहीं रचना जड़ के अंदर, या डि के माध्यम से इंजेक्शन), ताकि आप की तरह कुछ है:

static readonly Dictionary<Type, Func<object, ISummary>> _strategies = 
     new Dictionary<Type, Func<object, ISummary>>(); 

public static void Register<T>(Func<T, ISummary> strategy) 
{ 
    _strategies[typeof(T)] = input => strategy((T)input); 
} 

public ISummary CreateSummary(object input) 
{ 
    var type = input.GetType(); 

    Func<object, ISummary> strategy; 
    if (!_strategies.TryGetValue(type, out strategy)) 
     throw new ArgumentException($"No strategy registered for type {type}"); 

    return strategy(input); 
} 

तो, कहीं न कहीं अपनी संरचना जड़ में आप ठोस होता है विधि:

ISummary CreateEmployeeSummary(EmployeesData data) 
{ ... } 

ISummary CreateCarSummary(CarsData data) 
{ ... } 

// and finally register all concrete methods: 
Register<IEmployeesData>(d => CreateEmployeeSummary(d)); 
Register<ICarsData>(d => CreateCarsSummary(d)); 
संबंधित मुद्दे