2008-10-30 16 views
6

मैं सी # .NET में किसी व्यवसाय समस्या पर काम कर रहा हूं। मेरे पास सी और डब्ल्यू नामक दो वर्ग हैं जिन्हें अलग-अलग समय पर स्वतंत्र रूप से तुरंत चालू किया जाएगा।कक्षाओं के लिए सी # में एक अच्छा डिजाइन पैटर्न क्या है जो अन्य वर्गों को संदर्भित करने की आवश्यकता है?

कक्षा सी के किसी ऑब्जेक्ट को कक्षा डब्ल्यू के एन ... एन ऑब्जेक्ट्स के संदर्भों की आवश्यकता होती है, यानी एक सी ऑब्जेक्ट में एन डब्ल्यू ऑब्जेक्ट्स हो सकते हैं।

प्रत्येक डब्ल्यू ऑब्जेक्ट में कक्षा सी के बिल्कुल 1 ऑब्जेक्ट का संदर्भ होना आवश्यक है, यानी एक डब्ल्यू ऑब्जेक्ट एक सी ऑब्जेक्ट में निहित है।

कक्षा सी का एक वस्तु आमतौर पर पहले तत्काल होता है। बाद के बिंदु पर, इसकी डब्ल्यू सामग्री की खोज की जाती है, और तत्काल। इस बाद के बिंदु पर, मुझे एक दूसरे के लिए सी और डब्ल्यू वस्तुओं को संदर्भित करने की आवश्यकता है।

इसके लिए एक अच्छा डिजाइन पैटर्न क्या है? मेरे पास वास्तव में ऐसे मामले हैं जहां मेरे पास तीन या चार वर्ग शामिल हैं लेकिन हम इसे सरल रखने के लिए दो कक्षाओं के बारे में बात कर सकते हैं।

मैं कुछ सरल की तरह की सोच रहा था:

class C 
{ 
    public List<W> contentsW; 

} 

class W 
{ 
    public C containerC; 

} 

इस पल के लिए काम करेंगे, लेकिन मैं सभी संदर्भों और उनकी वैधता का ट्रैक रखने के कोड भी पर्याप्त मात्रा में लिखने के लिए होने का पूर्वानुमान कर सकते हैं। मैं केवल कंटेनर के उथले ताज़ा करने और सभी संदर्भित कक्षाओं के गहरे ताज़ा करने के लिए सड़क को कोड लागू करना चाहता हूं। क्या कोई अन्य दृष्टिकोण है और उनके फायदे क्या हैं?

11/3: पर संपादित करें अच्छे उत्तरों और अच्छी चर्चा के लिए सभी को धन्यवाद। आखिरकार मैंने जोप का जवाब चुना क्योंकि वह जो करना चाहता था उसके करीब आया, लेकिन अन्य उत्तरों ने भी मदद की। एक बार फिर धन्यवाद!

+0

सी और डब्ल्यू को पार संदर्भित कैसे किया जाता है? क्रॉस संदर्भित होने से पहले "डब्ल्यू" कौन रखता है? –

+0

जैसा कि कीथ ने मेरे जवाब में बताया, हमें यह पूछना है: इन वस्तुओं के सापेक्ष जीवनकाल एक-दूसरे के साथ क्या हैं? –

उत्तर

6

यदि आपके पास मार्टिन फाउलर की रिफैक्टरिंग पुस्तक है, तो बस "यूनिडायरेक्शनल एसोसिएशन टू बिडरेक्शनल" रिफैक्टरिंग का पालन करें।

मामले में आप यह नहीं है, यहाँ अपनी कक्षाओं पुनर्रचना के बाद कैसा दिखेगा का तरीका देखें:

class C 
{ 
    // Don't to expose this publicly so that 
    // no one can get behind your back and change 
    // anything 
    private List<W> contentsW; 

    public void Add(W theW) 
    { 
    theW.Container = this; 
    } 

    public void Remove(W theW) 
    { 
    theW.Container = null; 
    } 

    #region Only to be used by W 
    internal void RemoveW(W theW) 
    { 
    // do nothing if C does not contain W 
    if (!contentsW.Contains(theW)) 
     return; // or throw an exception if you consider this illegal 
    contentsW.Remove(theW); 
    } 

    internal void AddW(W theW) 
    { 
    if (!contentW.Contains(theW)) 
     contentsW.Add(theW); 
    } 
    #endregion 
} 

class W 
{ 
    private C containerC; 

    public Container Container 
    { 
    get { return containerC; } 
    set 
    { 
     if (containerC != null) 
     containerC.RemoveW(this); 
     containerC = value; 
     if (containerC != null) 
     containerC.AddW(this); 
    } 
    } 
} 

लें टिप्पणी है कि मैं List<W> निजी बना दिया है। सीधे सूची को उजागर करने के बजाय डब्ल्यूएस की सूची को गणनाकर्ता के माध्यम से एक्सपोजर करें।

उदा सार्वजनिक सूची GetWs() {इसे वापस करें। CONTentW.ToList(); }

उपरोक्त कोड स्वामित्व के हस्तांतरण को सही तरीके से संभालता है। मान लें कि आपके पास सी-सी 1 और सी 2 के दो उदाहरण हैं - और डब्ल्यू - डब्ल्यू 1 और डब्ल्यू 2 के उदाहरण हैं।

W1.Container = C1; 
W2.Container = C2; 

उपरोक्त कोड में, सी 1 में डब्ल्यू 1 और सी 2 में डब्ल्यू 2 शामिल है। आप पुन: असाइन डब्ल्यू 2 सी 1 के लिए तो

W2.Container = C1; 

फिर सी 2 शून्य आइटम होंगे और C1 दो आइटम होगा - W1 और W2। आप एक अस्थायी डब्ल्यू

W2.Container = null; 

इस मामले में, डब्ल्यू 2 सी 1 की सूची से निकाल दिया जाएगा हो सकता है और यह कोई कंटेनर होगा। आप डब्ल्यू के कंटेनरों में हेरफेर करने के लिए सी से जोड़ें और निकालें विधियों का भी उपयोग कर सकते हैं - इसलिए C1.Add (W2) स्वचालित रूप से W2 को इसके मूल कंटेनर से हटा देगा और इसे नए में जोड़ देगा।

2

हममम, लगता है कि आप लगभग यह मिल गया, एक छोटी सी गड़बड़ के साथ - आप

सी

भीतर सूची के अलावा नियंत्रित करने के लिए सक्षम होना चाहिए जैसे,

class C 
{ 
    private List<W> _contentsW; 

    public List<W> Contents 
    { 
     get { return _contentsw; } 
    } 

    public void AddToContents(W content); 
    { 
     content.Container = this; 
     _contentsW.Add(content); 
    } 
} 

जाँच के लिए, आप बस अपनी सूची के माध्यम से पुनरावृति करने के लिए है, मुझे लगता है:

foreach (var w in _contentsW) 
{ 
    if (w.Container != this) 
    { 
     w.Container = this; 
    } 
} 

सुनिश्चित नहीं हैं कि तुम क्या जरूरत है।

यह महसूस करें कि डब्ल्यू के कई उदाहरण हो सकते हैं जिनके समान मूल्य होंगे लेकिन अलग-अलग सी कंटेनर हो सकते हैं।

+0

जो सी और डब्ल्यू के जीवनकाल के आधार पर काम कर सकता है या नहीं। यदि सी को डब्ल्यू से पहले मरना है, तो डब्ल्यू को वास्तव में सी –

+0

के कमजोर संदर्भ की आवश्यकता है, मुझे लगता है कि इसीलिए मैंने पूछा कि डब्ल्यू को कैसे संभाला जाना चाहिए। आवश्यकता डब्ल्यू के अस्तित्व के बारे में चिंता करने के लिए पर्याप्त सरल लगती है। शायद एक और ठोस अवधारणा समस्या को स्पष्ट करने में मदद करेगी। –

0

इसके लिए एक विकल्प System.ComponentModel के अंतर्गत IContainer और IComponent इंटरफेस को लागू करना होगा। सी कंटेनर होगा, और डब्ल्यू घटक। ComponentCollection वर्ग तो अपने डब्ल्यू उदाहरण के लिए भंडारण के रूप में काम करेगा, और IComponent.Site सी

वापस करने के लिए लिंक प्रदान करेगा
3

मैं आम तौर पर यह कुछ इस तरह करते हैं:

class C 
{ 
    private List<W> _contents = new List<W>(); 
    public IEnumerable<W> Contents 
    { 
     get { return _contents; } 
    } 

    public void Add(W item) 
    { 
     item.C = this; 
     _contents.Add(item); 
    } 
} 

इस प्रकार, आपके सामग्री संपत्ति केवल पढ़ने योग्य है और आप केवल अपनी कुल विधि के माध्यम से आइटम जोड़ते हैं।

1

पर Jons उत्तर विस्तार ....

आप अगर डब्ल्यू नहीं है सी जीवित रखने के लिए माना जाता कमजोर संदर्भ पड़ सकता है।

भी ... ऐड अधिक जटिल यदि आप स्वामित्व स्थानांतरित करना चाहते होना चाहिए ...

public void AddToContents(W content); 
{ 
    if(content.Container!=null) content.Container.RemoveFromContents(content); 
    content.Container = this; 
    _contentsW.Add(content); 
} 
0

यह पैटर्न मैं का उपयोग करें।

public class Parent { 
    public string Name { get; set; } 
    public IList<Child> Children { get { return ChildrenBidi; } set { ChildrenBidi.Set(value); } } 
    private BidiChildList<Child, Parent> ChildrenBidi { get { 
     return BidiChildList.Create(this, p => p._Children, c => c._Parent, (c, p) => c._Parent = p); 
    } } 
    internal IList<Child> _Children = new List<Child>(); 
} 

public class Child { 
    public string Name { get; set; } 
    public Parent Parent { get { return ParentBidi.Get(); } set { ParentBidi.Set(value); } } 
    private BidiParent<Child, Parent> ParentBidi { get { 
     return BidiParent.Create(this, p => p._Children,() => _Parent, p => _Parent = p); 
    } } 
    internal Parent _Parent = null; 
} 

जाहिर है, मैं वर्गों BidiParent<C, P> और BidiChildList<C, P>, बाद वाले का लागू करता IList<C>, आदि परदे के पीछे के अपडेट आंतरिक क्षेत्रों के माध्यम से किया जाता है, जबकि जो इस डोमेन मॉडल का उपयोग करता कोड से अपडेट माध्यम से किया जाता सार्वजनिक गुण।

संबंधित मुद्दे

 संबंधित मुद्दे