2013-02-26 112 views
5

मान लीजिए कि परिदृश्य एक अपरिवर्तनीय प्रकार को लागू करने की अनुमति नहीं देता है। उस धारणा के बाद, मैं राय/उदाहरणों को सही तरीके से डिजाइन करने के तरीके पर विचार करना चाहता हूं कि इसका उपभोग करने के बाद, अपरिवर्तनीय हो जाता है।एक म्यूटेबल क्लास डिज़ाइन करें जो इसके उपभोग के बाद अपरिवर्तनीय हो जाता है

public class ObjectAConfig { 

    private int _valueB; 
    private string _valueA; 
    internal bool Consumed { get; set; } 

    public int ValueB { 
    get { return _valueB; } 
    set 
    { 
     if (Consumed) throw new InvalidOperationException(); 
     _valueB = value; 
    } 
    } 

    public string ValueA { 
    get { return _valueA; } 
    set 
    { 
     if (Consumed) throw new InvalidOperationException(); 
     _valueA = value; 
    } 
    } 
} 

जब ObjectA खपत ObjectAConfig:

public ObjectA { 

    public ObjectA(ObjectAConfig config) { 

    _config = config; 
    _config.Consumed = true; 
    } 
} 

मैं संतुष्ट है कि इस बस काम करता है नहीं कर रहा हूँ, मैं, के रूप में कहा एक बेहतर पैटर्न (बाहर रखा गया हो, तो जानना चाहते हैं, ObjectAConfig द्वारा अपरिवर्तनीय बना शुरुआत से डिजाइन)।

  • भावना Once<T> की तरह एक इकाई है कि अनुमति देते हैं लिपटे मूल्य केवल एक बार प्रारंभ करने के लिए परिभाषित कर सकते हैं:

    उदाहरण के लिए

    ?

  • एक ऐसे प्रकार को परिभाषित कर सकता है जो प्रकार को एक निजी क्षेत्र में बदल देता है? अर्थात आप इसे रोक सकते हैं -

+0

* क्यों * आप एक अपरिवर्तनीय प्रकार को लागू नहीं कर सकते? यदि आपने उस वास्तविक समस्या को समझाया है जिसे आप हल करने का प्रयास कर रहे हैं तो इससे मदद मिलेगी। –

+0

[यह प्रश्न] (http://stackoverflow.com/questions/4168382) में कुछ दिलचस्प पैटर्न समान चीजें कर रहे हैं। –

उत्तर

10

क्या आप कभी कभी कार्यान्वित कर रहे हैं नाम "popsicle immutability" के अंतर्गत चला जाता है। आपका वर्तमान दृष्टिकोण काम करेगा - वास्तव में मैं उस पैटर्न को कई स्थानों पर स्वयं उपयोग करता हूं।

private void SetField<T>(ref T field, T value) { 
    if (Consumed) throw new InvalidOperationException(); 
    field = value; 
} 
public int ValueB { 
    get { return _valueB; } 
    set { SetField(ref _valueB, value); } 
}  
public string ValueA { 
    get { return _valueA; } 
    set { SetField(ref _valueA, value); } 
} 

एक और संबंधित दृष्टिकोण है, हालांकि: एक बिल्डर

आप शायद कुछ दोहराव की तरह कुछ के माध्यम से कम कर सकते हैं।

public interface IConfig 
{ 
    string ValueA { get; } 
    int ValueB { get; } 
} 
public class ObjectAConfig : IConfig 
{ 
    private class ImmutableConfig : IConfig { 
     private readonly string valueA; 
     private readonly int valueB; 
     public ImmutableConfig(string valueA, int valueB) 
     { 
      this.valueA = valueA; 
      this.valueB = valueB; 
     } 
    } 
    public IConfig Build() 
    { 
     return new ImmutableConfig(ValueA, ValueB); 
    } 
    ... snip: implementation of ObjectAConfig 
} 

यहाँ IConfig की वास्तव में एक अपरिवर्तनीय कार्यान्वयन है, और अपने मूल कार्यान्वयन: उदाहरण के लिए, अपने मौजूदा कक्षा लेने। यदि आप जमे हुए संस्करण चाहते हैं, तो Build() पर कॉल करें।

+0

+1 @ मार्क गर्वेल, मैं वास्तव में नमूनों की सराहना करता हूं; लेकिन मैं इस पैटर्न को एक ठोस अंतर्निहित अवधारणा के नाम के रूप में और भी सराहना करता हूं। मैं ई। लिपर्ट लेखों में भी गोता लगाऊंगा। – jay

+0

popsicle प्रतिरक्षा थ्रेड-सुरक्षित होने के लिए, सभी ऑब्जेक्ट सेटर्स और फ्रीज विधि को लॉकिंग या अन्य ऐसे साधनों का उपयोग करना चाहिए ताकि यह सुनिश्चित किया जा सके कि किसी ऑब्जेक्ट को संशोधित किए जाने पर जमे हुए नहीं किया जा सकता है [यदि कोई है तो इंटरलॉक प्राइमेटिव का उपयोग करना संभव हो सकता है अनुचित धागा उपयोग करने के इच्छुक 'फ्रीज' विधि में अपवाद ट्रिगर करें]। ध्यान दें कि यहां तक ​​कि यदि कोई वर्ग खुद को थ्रेड-सुरक्षित के रूप में विज्ञापित नहीं करता है, फिर भी यह आश्वस्त होना चाहिए कि यदि किसी उदाहरण ने खुद को अपरिवर्तनीय बताया है, और इसके राज्य के किसी भी पहलू की सूचना दी है, तो वह पहलू कभी भी बदलेगा नहीं। – supercat

+0

@supercar कई मामलों में यह मानना ​​उचित है कि कुछ अलग क्षेत्र में जमे हुए, जमे हुए, और *** केवल तभी कई धागे के संपर्क में आ जाएंगे। –