2010-04-16 12 views
9

मैं अगर मैं अपनी परियोजनाओं में से एक के सॉफ्टवेयर वास्तुकला बदलना चाहिए सोच रहा हूँ।क्या विरासत कार्यक्षमता को खाली करने का अच्छा अभ्यास है जिसका उपयोग नहीं किया जाएगा?

मैं एक परियोजना के लिए सॉफ्टवेयर विकसित कर रहा हूं जहां दो पक्ष (वास्तव में एक मेजबान और एक डिवाइस) साझा कोड का उपयोग करते हैं। इससे मदद मिलती है क्योंकि साझा डेटा, उदा। enums एक केंद्रीय जगह में संग्रहीत किया जा सकता है।

मैं डिवाइस और मेजबान के बीच डेटा स्थानांतरित करने के लिए जिसे "चैनल" कहता हूं उसके साथ काम कर रहा हूं। प्रत्येक चैनल को डिवाइस और मेजबान पक्ष पर लागू किया जाना है। हमारे पास विभिन्न प्रकार के चैनल, सामान्य और विशेष चैनल हैं जो माप डेटा स्थानांतरित करते हैं।

मेरे वर्तमान समाधान एक सार आधार वर्ग में साझा कोड है। वहां से कोड दोनों तरफ के बीच विभाजित है। चूंकि यह निकला है कि कुछ मामले हैं जब हम कोड साझा करते थे लेकिन हम इसे साझा नहीं कर सकते हैं, हमें इसे प्रत्येक तरफ लागू करना होगा।

डीआरवाई का सिद्धांत (स्वयं को दोहराना न करें) कहता है कि आपके पास कोड दो बार नहीं होना चाहिए।

मेरे सोचा अब जैसे की कार्यक्षमता को श्रेणीबद्ध करने के लिए था डिवाइस कोड पर सार माप माप चैनल और मेजबान पक्ष साझा कोड के साथ एक सार वर्ग में। इसका मतलब है कि एक बार जब हम उस चैनल के लिए डिवाइस या मेजबान पक्ष के लिए एक वास्तविक कक्षा बनाते हैं तो हमें दूसरी तरफ उपयोग की जाने वाली कार्यक्षमता को छिपाना होगा।

public abstract class ChannelAbstract 
{ 
    protected void ChannelAbstractMethodUsedByDeviceSide() { } 
    protected void ChannelAbstractMethodUsedByHostSide()  { } 
} 

public abstract class MeasurementChannelAbstract : ChannelAbstract 
{ 
    protected void MeasurementChannelAbstractMethodUsedByDeviceSide() { } 
    protected void MeasurementChannelAbstractMethodUsedByHostSide()  { } 
} 

public class DeviceMeasurementChannel : MeasurementChannelAbstract 
{ 
    public new void MeasurementChannelAbstractMethodUsedByDeviceSide() 
    { 
     base.MeasurementChannelAbstractMethodUsedByDeviceSide(); 
    } 

    public new void ChannelAbstractMethodUsedByDeviceSide() 
    { 
     base.ChannelAbstractMethodUsedByDeviceSide(); 
    } 
} 

public class HostMeasurementChannel : MeasurementChannelAbstract 
{ 
    public new void MeasurementChannelAbstractMethodUsedByHostSide() 
    { 
     base.MeasurementChannelAbstractMethodUsedByHostSide(); 
    } 

    public new void ChannelAbstractMethodUsedByHostSide() 
    { 
     base.ChannelAbstractMethodUsedByHostSide(); 
    } 
} 

अब, DeviceMeasurementChannel केवल डिवाइस पक्ष के लिए कार्यक्षमता MeasurementChannelAbstract से उपयोग कर रहा है:

करने के लिए इस एक स्वीकार्य बात है। सभी तरीकों में घोषित करने से/MeasurementChannelAbstract के सदस्यों protected आप new कीवर्ड का उपयोग करने के लिए है बाहर से पहुँचा जा सकता है कि कार्यक्षमता को सक्षम करने।

क्या यह स्वीकार्य है या क्या कोई नुकसान, चेतावनी इत्यादि हैं जो कोड का उपयोग करते समय बाद में उत्पन्न हो सकती हैं?

+0

आपने कई स्थानों पर कहा है कि वे कोड साझा करते हैं और फिर कई अन्य स्थानों पर आपको कुछ अलग करना पड़ता है? उनके बीच वास्तव में क्या साझा किया जाता है जो आपको अलग करने के लिए रोक देता है? –

+0

@ जोन केज: फिलहाल (उपरोक्त उदाहरण में स्वयं आर्किटेक्चर को बदलने से पहले) मेरे पास डिवाइस मापन ChannelAbstract और HostMeasurementChannelAbstract है। डिवाइस पक्ष के लिए एक और मेजबान पक्ष के लिए एक। दोनों चैनल डिवाइसChannelAbstract और HostChannelAbstract से क्रमशः प्राप्त होते हैं। इन दो को एक साझा अमूर्त वर्ग से प्राप्त किया जाता है जिसे चैनल एबस्ट्र कहा जाता है। अब मेरे पास दो चर हैं जिनके सभी माप चैनलों को सामान्य चैनल नहीं होना चाहिए। यही समस्या है। उम्मीद है कि इससे आपको भ्रमित करने की तुलना में यह स्पष्ट किया गया है: एस –

उत्तर

5

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

, यह भी व्यावहारिकता पर विचार सही OOP में सब कुछ मानचित्रण लक्ष्य नहीं है, लक्ष्य एक काम प्रोग्राम है जो बहुत बड़ा दर्द के बिना पोषणीय है।

+0

@ पासी Savolainen: फिलहाल मैं यह सुनिश्चित करने के लिए किसी अन्य तरीके से नहीं सोच सकता कि मेजबान/डिवाइस पक्ष पर कोड दोहराया नहीं गया है, जो साझा सार वर्गों को साझा करने के अलावा किसी भी पक्ष की कार्यक्षमता है। इस धारणा के तहत कि रखरखाव आसान होना आसान है, मुझे अपने "उपरोक्त" कार्यक्षमता के उपर्युक्त दृष्टिकोण के लिए जाना होगा जो संबंधित पक्ष (डिवाइस/होस्ट) के लिए उचित नहीं है। इस तरह से मैं कम से कम यह सुनिश्चित कर सकता हूं कि डिवाइस/मेजबान पक्ष पर किसी चैनल के कार्यान्वयन को समान आधार वर्ग, जानकारी साझा करने से प्राप्त होगा। –

+0

मैंने आपका जवाब स्वीकार कर लिया क्योंकि मुझे लगता है कि यह उस स्थिति के सबसे नज़दीक आता है जिसका हम सामना कर रहे हैं। सिर्फ रिकॉर्ड के लिए, हम अपने वर्तमान दृष्टिकोण के साथ रह रहे हैं जहां हम उसी वर्ग में दोनों पक्षों के लिए कोड रखने के साथ आने वाले भ्रम से बचने के लिए डिवाइस/होस्ट साइड कार्यान्वयन के लिए कक्षाओं को विभाजित करते हैं। यह एक आसान निर्णय नहीं था, लेकिन कोड को समझने की कोशिश कर रहे अन्य डेवलपर्स के बारे में सोचते हुए मुझे लगता है कि यह सबसे अच्छा निर्णय है। यह सही ओओपी में मैप नहीं करता है लेकिन यह काम करता है और स्पष्ट है। –

0

यह मुझे लगता है कि आपने यह निर्धारित नहीं किया है कि कोड के कौन से बिट साझा किए गए हैं। इसे और अधिक समझ में विभिन्न तरीकों जो दोनों पक्षों ने फोन होने के बजाय MeasurementChannelAbstract में सभी सामान्य/साझा किया गया उत्पाद रखने के लिए नहीं बना सकते हैं? मैंने सोचा होगा कि उनको विरासत में होना चाहिए?

7

आप विरासत के साथ समस्या को हल कर सकते हैं, इस तरह:

public abstract class MeasurementChannelAbstract 
{ 
    protected abstract void Method(); 
} 

public class DeviceMeasurementChannel : MeasurementChannelAbstract 
{ 
    public void Method() 
    { 
     // Device side implementation here. 
    } 
} 

public class HostMeasurementChannel : MeasurementChannelAbstract 
{ 
    public void Method() 
    { 
     // Host side implementation here. 
    } 
} 

... या रचना से, रणनीति पद्धति का उपयोग कर, इस तरह:

public class MeasurementChannel 
{ 
    private MeasurementStrategyAbstract m_strategy; 

    public MeasurementChannel(MeasurementStrategyAbstract strategy) 
    { 
     m_strategy = strategy; 
    } 

    protected void Method() 
    { 
     m_strategy.Measure(); 
    } 
} 

public abstract class MeasurementStrategyAbstract 
{ 
    protected abstract void Measure(); 
} 

public class DeviceMeasurementStrategy : MeasurementStrategyAbstract 
{ 
    public void Measure() 
    { 
     // Device side implementation here. 
    } 
} 

public class HostMeasurementStrategy : MeasurementStrategyAbstract 
{ 
    public void Measure() 
    { 
     // Host side implementation here. 
    } 
} 

मुझे ऐसा लगता है कि आप दोनों मानक/मापन चैनल और डिवाइस/होस्ट चैनल दोनों के बीच अपनी विरासत पदानुक्रम को विभाजित करना चाहते हैं। एक तरीका यह है करने के लिए कई विरासत के साथ है - लेकिन सी # बहु उत्तराधिकार का समर्थन नहीं करता (इंटरफेस के लिए छोड़कर), और ज्यादातर मामलों में एक डिजाइन संरचना पर आधारित सरल हो जाएगा।

+0

@richj: मुझे लगता है कि आपको यह अधिकार मिला है। मेरे पास मानक और माप चैनल दोनों हैं (जहां एक माप चैनल माप चैनल की कार्यक्षमता बढ़ाता है)। मुझे डिवाइस की तरफ और मेजबान पक्ष के लिए अलग-अलग कार्यान्वयन की भी आवश्यकता है। जैसा कि आपने कहा, सी # एकाधिक विरासत नहीं करता है। इसलिए मैं खुद से पूछता हूं कि विरासत की एक श्रृंखला होने के लिए ठीक है (यह स्वीकार करना कि कुछ वर्गों में होस्ट और डिवाइस दोनों पक्षों के लिए कार्यक्षमता होगी) और अंतिम चरण में मेजबान/डिवाइस चैनल में अलगाव करें (कार्यक्षमता को खाली करना जरूरत नहीं)। –

+0

@richj: विरासत का उपयोग कर समस्या को हल करने का आपका उदाहरण मेरे लिए काम नहीं करता है क्योंकि मेरे पास मापनमेंट चैनल एबस्ट्रेट में विधियां हैं जिनका उपयोग केवल डिवाइस की तरफ या दूसरी तरफ से किया जाता है। मुझे पता है कि मैं उन्हें डिवाइस मापन ChannelAbstract और HostMeasurementChannelAbstract पर ले जा सकता हूं जो मापनमेंटChannelAbstract से प्राप्त होगा। समस्या यह है कि उदा। तापमान चैनेल जिसे दोनों पक्षों के लिए लागू करने की आवश्यकता है उन्हें इन दो वर्गों में से एक से उत्तराधिकारी होना होगा और तापमानChannelAbstract (जहां इस चैनल के लिए साझा डेटा परिभाषित किया जा सकता है) से उत्तराधिकारी नहीं होना चाहिए। –

+0

मुझे आश्चर्य है कि अगर अमूर्त कक्षाओं के बजाय इंटरफेस के शुरुआती बिंदु से समस्या आती है तो मदद मिलेगी। इंटरफेस होंगे: आईसीएचनल, आईएसएड चैनल: आईसीएचनल, इमेजमेंट चैनल: आईसीएचनल, आईएसएड मापनमेंट चैनल: आईएसएड चैनल, इमेजमेंट चैनल। इस विचार का उपयोग करके आप प्रत्येक प्रकार के विविधता के लिए एक ठोस कार्यान्वयन प्रदान कर सकते हैं, या आप प्रत्येक प्रकार के लिए एक ठोस कार्यान्वयन प्रदान कर सकते हैं और रणनीतियों (डिवाइससाइडस्ट्रेटी, होस्टसाइडस्ट्रेटी, ...) का उपयोग करके विविधताओं के साथ सौदा कर सकते हैं। – richj

2

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

यह "Single Responsibility Principle" कहा जाता है और यह है अच्छा OO डिजाइन के लिए एक महत्वपूर्ण एक है।

(अच्छे ओओ डिजाइन पर अधिक के लिए, मैं सभी ठोस सिद्धांतों के माध्यम से काम करने की सलाह देता हूं)।

0

इसलिए मैं अपने आप को पूछते हैं कि यह ठीक है विरासत (स्वीकार करने कि कुछ कक्षाएं दोनों मेजबान और उपकरण पक्ष के लिए कार्यक्षमता होगी) के एक निरंतर सेट करने के लिए और मेजबान/उपकरण चैनल में जुदाई करना अंतिम चरण पर

मुझे लगता है कि यह ठीक है (कार्यक्षमता जो की जरूरत नहीं है बाहर रिक्त)। लेकिन आप कार्यक्षमता को खाली कर सकते हैं जिसे SimpleChannel और MeasurementChannel के लिए अलग-अलग इंटरफेस का उपयोग करके आवश्यक नहीं है।

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