सार बेस क्लास इंटरव्यूज़ विद बिहेवियर?


14

मुझे अपने C # प्रोजेक्ट के लिए एक श्रेणी पदानुक्रम डिजाइन करने की आवश्यकता है। मूल रूप से, वर्ग की कार्यक्षमताएं WinForms कक्षाओं के समान हैं तो आइए WinForms टूलकिट को एक उदाहरण के रूप में लेते हैं। (हालांकि, मैं WinForms या WPF का उपयोग नहीं कर सकता।)

कुछ मुख्य गुण और कार्य हैं जिन्हें हर वर्ग को प्रदान करने की आवश्यकता है। आयाम, स्थिति, रंग, दृश्यता (सही / गलत), ड्रा विधि, आदि।

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

कोड इस तरह दिखता है:

abstract class Control
{
    public int Width { get; set; }

    public int Height { get; set; }

    public int BackColor { get; set; }

    public int X { get; set; }

    public int Y { get; set; }

    public int BorderWidth { get; set; }

    public int BorderColor { get; set; }

    public bool Visible { get; set; }

    public Rectangle ClipRectange { get; protected set; }

    abstract public void Draw();
}

कुछ नियंत्रणों में अन्य नियंत्रण शामिल हो सकते हैं, कुछ केवल निहित (बच्चों के रूप में) हो सकते हैं इसलिए मैं इन कार्यात्मकताओं के लिए दो इंटरफेस बनाने की सोच रहा हूं:

interface IChild
{
    IContainer Parent { get; set; }
}

internal interface IContainer
{
    void AddChild<T>(T child) where T : IChild;
    void RemoveChild<T>(T child) where T : IChild;
    IChild GetChild(int index);
}

WinForms प्रदर्शन पाठ को नियंत्रित करता है इसलिए यह इंटरफ़ेस में भी जाता है:

interface ITextHolder
{
    string Text { get; set; }
    int TextPositionX { get; set; }
    int TextPositionY { get; set; }
    int TextWidth { get; }
    int TextHeight { get; }

    void DrawText();
}

कुछ नियंत्रणों को उनके मूल नियंत्रण के अंदर डॉक किया जा सकता है:

enum Docking
{ 
    None, Left, Right, Top, Bottom, Fill
}

interface IDockable
{
    Docking Dock { get; set; }
}

... और अब कुछ ठोस वर्ग बनाते हैं:

class Panel : Control, IDockable, IContainer, IChild {}
class Label : Control, IDockable, IChild, ITextHolder {}
class Button : Control, IChild, ITextHolder, IDockable {}
class Window : Control, IContainer, IDockable {}

पहली "समस्या" मैं यहां सोच सकता हूं कि एक बार प्रकाशित होने के बाद इंटरफेस मूल रूप से पत्थर में सेट होते हैं। लेकिन मान लेते हैं कि मैं भविष्य में उन्हें परिवर्तन करने की आवश्यकता से बचने के लिए अपने इंटरफेस को अच्छा बनाने में सक्षम हूं।

इस डिजाइन में एक और मुद्दा यह है कि इन वर्गों में से प्रत्येक को इसे लागू करने की आवश्यकता होगी और कोड का दोहराव जल्दी होगा। उदाहरण के लिए लेबल और बटन में ड्राटेक्स्ट () विधि ITextHolder इंटरफ़ेस से या बच्चों के IContainer प्रबंधन से प्राप्त हर वर्ग से प्राप्त होती है।

इस मुद्दे के लिए मेरा समाधान इस "डुप्लिकेटेड" कार्यात्मकताओं को समर्पित एडेप्टर और उन्हें कॉल करने के लिए लागू करना है। तो लेबल और बटन दोनों में एक TextHolderAdapter सदस्य होता है जिसे ITextHolder इंटरफ़ेस से विरासत में मिली विधियों के अंदर कहा जाएगा।

मुझे लगता है कि इस डिज़ाइन से मुझे बेस क्लास में कई सामान्य कार्यात्मकताओं से बचना चाहिए जो कि आभासी तरीकों और अनावश्यक "शोर" के साथ जल्दी से फूला हुआ हो सकता है। व्यवहार के परिवर्तन का विस्तार एडेप्टर द्वारा किया जाएगा और नियंत्रण-व्युत्पन्न वर्ग से नहीं।

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

मुझे यह जोड़ना चाहिए कि लगभग 100% संभावना है कि भविष्य की आवश्यकताएं नई कक्षाओं और नई कार्यक्षमता के लिए कॉल करेंगी।


क्यों बस से विरासत में नहीं System.ComponentModel.Componentया System.Windows.Forms.Controlया अन्य मौजूदा आधार वर्ग के किसी भी? आपको अपना खुद का नियंत्रण पदानुक्रम बनाने और खरोंच से इन सभी कार्यों को फिर से परिभाषित करने की आवश्यकता क्यों है?
कोड़ी ग्रे

3
IChildएक भयानक नाम की तरह लगता है।
रेयानोस

@ कोडी: पहले, मैं WinForms या WPF असेंबलियों का उपयोग नहीं कर सकता, दूसरा - चलो, यह एक डिज़ाइन समस्या का एक उदाहरण है जिसके बारे में मैं पूछ रहा हूं। यदि आपके लिए यह आसान लगता है कि आकार या जानवर हैं। मेरी कक्षाओं को WinForms नियंत्रणों के समान व्यवहार करने की आवश्यकता है लेकिन हर तरह से नहीं और बिल्कुल उनकी तरह नहीं
grapkulec

2
यह कहने का कोई मतलब नहीं है कि आप WinForms या WPF असेंबलियों का उपयोग नहीं कर सकते हैं, फिर भी आप जो भी कस्टम नियंत्रण ढांचा बनाने के लिए उपयोग करने में सक्षम होंगे। यह पहिये का फिर से आविष्कार करने का एक गंभीर मामला है, और मैं इसके संभावित उद्देश्य की कल्पना नहीं कर सकता। लेकिन अगर आप बिल्कुल, WinForms नियंत्रण के उदाहरण का पालन ​​क्यों नहीं करना चाहिए ? इससे यह प्रश्न बहुत अप्रचलित हो जाता है।
कोड़ी ग्रे

1
@graphkulec इसीलिए यह एक टिप्पणी है :) अगर मेरे पास देने के लिए वास्तविक उपयोगी प्रतिक्रिया होती तो मैं आपके प्रश्न का उत्तर देता। यह अभी भी एक भयानक नाम है;)
रेयानोस

जवाबों:


5

[1] अपनी संपत्तियों में आभासी "गेटर्स" और "सेटर" जोड़ें , मुझे एक और नियंत्रण पुस्तकालय को हैक करना पड़ा, क्योंकि मुझे यह सुविधा चाहिए:

abstract class Control
{
    // internal fields for properties
    protected int _Width;
    protected int _Height;
    protected int _BackColor;
    protected int _X;
    protected int _Y;
    protected bool Visible;

    protected int BorderWidth;
    protected int BorderColor;


    // getters & setters virtual !!!

    public virtual int getWidth(...) { ... }
    public virtual void setWidth(...) { ... }

    public virtual int getHeight(...) { ... }
    public virtual void setHeight(...) { ... }

    public virtual int getBackColor(...) { ... }
    public virtual void setBackColor(...) { ... }

    public virtual int getX(...) { ... }
    public virtual void setX(...) { ... }

    public virtual int getY(...) { ... }
    public virtual void setY(...) { ... }

    public virtual int getBorderWidth(...) { ... }
    public virtual void setBorderWidth(...) { ... }

    public virtual int getBorderColor(...) { ... }
    public virtual void setBorderColor(...) { ... }

    public virtual bool getVisible(...) { ... }
    public virtual void setVisible(...) { ... }

    // properties WITH virtual getters & setters

    public int Width { get getWidth(); set setWidth(value); }

    public int Height { get getHeight(); set setHeight(value); }

    public int BackColor { get getBackColor(); set setBackColor(value); }

    public int X { get getX(); set setX(value); }

    public int Y { get getY(); set setY(value); }

    public int BorderWidth { get getBorderWidth(); set setBorderWidth(value); }

    public int BorderColor { get getBorderColor(); set setBorderColor(value); }

    public bool Visible { get getVisible(); set setVisible(value); }

    // other methods

    public Rectangle ClipRectange { get; protected set; }   
    abstract public void Draw();
} // class Control

/* concrete */ class MyControl: Control
{
    public override bool getVisible(...) { ... }
    public override void setVisible(...) { ... }
} // class MyControl: Control

मुझे पता है कि यह सुझाव अधिक "क्रिया" या जटिल है, लेकिन, वास्तविक दुनिया में इसका बहुत उपयोगी है।

[२] "IsEnabled" संपत्ति जोड़ें, "IsReadOnly" के साथ भ्रमित न हों:

abstract class Control
{
    // internal fields for properties
    protected bool _IsEnabled;

    public virtual bool getIsEnabled(...) { ... }
    public virtual void setIsEnabled(...) { ... }

    public bool IsEnabled{ get getIsEnabled(); set setIsEnabled(value); }
} // class Control

इसका मतलब है कि आपको अपना नियंत्रण दिखाना पड़ सकता है, लेकिन कोई जानकारी नहीं दिखाना चाहिए।

[३] "IsReadOnly" संपत्ति जोड़ें, "IsEnabled" के साथ भ्रमित न करें:

abstract class Control
{
    // internal fields for properties
    protected bool _IsReadOnly;

    public virtual bool getIsReadOnly(...) { ... }
    public virtual void setIsReadOnly(...) { ... }

    public bool IsReadOnly{ get getIsReadOnly(); set setIsReadOnly(value); }
} // class Control

इसका मतलब है कि नियंत्रण जानकारी प्रदर्शित कर सकता है, लेकिन उपयोगकर्ता द्वारा नहीं बदला जा सकता है।


हालाँकि मुझे बेस क्लास में ये सभी वर्चुअल तरीके पसंद नहीं हैं लेकिन मैं डिजाइन के बारे में अपनी सोच में उन्हें दूसरा मौका दूंगा। और आपने मुझे याद दिलाया कि मुझे वास्तव में IsReadOnly संपत्ति की आवश्यकता है :)
grapkulec

@grapkulec चूंकि इसका आधार वर्ग है, इसलिए आपको यह निर्दिष्ट करना होगा कि व्युत्पन्न वर्गों में वे गुण होंगे, लेकिन, यह कि व्यवहार को नियंत्रित करने वाले तरीके प्रत्येक कक्षा के
पर्पस

mmkey, मैं आपकी बात देखता हूं और उत्तर देने के लिए समय देने के लिए धन्यवाद देता हूं
grapkulec

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

3

अच्छा प्रश्न! पहली बात जो मैंने नोटिस की वह यह है कि ड्रा विधि में कोई पैरामीटर नहीं है, यह कहाँ आकर्षित करता है? मुझे लगता है कि इसे कुछ सर्फेस या ग्राफिक्स ऑब्जेक्ट को पैरामीटर (निश्चित रूप से इंटरफ़ेस के रूप में) प्राप्त करना चाहिए।

एक और बात जो मुझे अजीब लगती है वो है IContainer इंटरफ़ेस। इसमें एक ऐसी GetChildविधि है जो एकल बच्चे को लौटाती है और जिसमें कोई पैरामीटर नहीं है - हो सकता है कि यह एक संग्रह लौटा दे या यदि आप किसी इंटरफ़ेस में ड्रा विधि को स्थानांतरित करते हैं तो वह इस इंटरफ़ेस को लागू कर सकता है और एक ड्रा विधि हो सकती है जो इसे उजागर किए बिना अपने आंतरिक बच्चों के संग्रह को आकर्षित कर सकती है। ।

शायद विचारों के लिए आप WPF को भी देख सकते हैं - यह मेरी राय में एक बहुत अच्छी तरह से डिज़ाइन किया गया ढांचा है। इसके अलावा आप संरचना और सज्जाकार डिजाइन पैटर्न पर एक नज़र डाल सकते हैं। पहला एक कंटेनर तत्वों के लिए उपयोगी हो सकता है और दूसरा तत्वों की कार्यक्षमता जोड़ने के लिए। मैं यह नहीं कह सकता कि पहली नज़र में यह कितना अच्छा काम करेगा, लेकिन यहाँ मुझे लगता है:

दोहराव से बचने के लिए आपके पास कुछ मूल तत्व जैसे पाठ तत्व हो सकते हैं। फिर आप इन आदिमों का उपयोग करके अधिक जटिल तत्वों का निर्माण कर सकते हैं। उदाहरण के लिए, एक Borderऐसा तत्व है जिसमें एक ही बच्चा है। जब आप इसकी Drawविधि कहते हैं तो यह एक सीमा और एक पृष्ठभूमि खींचता है और फिर अपने बच्चे को सीमा के अंदर खींचता है। एक TextElementही कुछ पाठ खींचता है। अब यदि आप एक बटन चाहते हैं, तो आप उन दो आदिमों की रचना करके, सीमा के अंदर पाठ डालकर एक का निर्माण कर सकते हैं। यहां बॉर्डर एक डेकोरेटर की तरह है।

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


1
लापता params एक समस्या नहीं है, यह सब के बाद वास्तविक तरीकों का सिर्फ एक स्केच है। WPF के बारे में मैंने उनके विचार के आधार पर लेआउट सिस्टम तैयार किया है, इसलिए मुझे लगता है कि मेरे पास पहले से ही रचना भाग है, क्योंकि सज्जाकारों के लिए मुझे इसके बारे में सोचना होगा। आदिम तत्वों के बारे में आपका विचार उचित लगता है और मैं इसे ज़रूर आज़माता हूँ। धन्यवाद!
11

@grapkulec आपका स्वागत है! परम के बारे में - हाँ, यह ठीक है, मैं सिर्फ यह सुनिश्चित करना चाहता था कि मैं आपके इरादों को सही ढंग से समझूं। मुझे खुशी है कि आपको यह विचार पसंद आया। सौभाग्य!

2

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

मैंने वास्तव में इस तरह के एक दृष्टिकोण (मेरे रेंडरिंग इंजन में) का उपयोग किया है, जहां प्रत्येक इंटरफ़ेस ने व्यवहार उपसमूह के अपेक्षित व्यवहार को परिभाषित किया। उदाहरण के लिए, IUpdateable, ICollidable, IRenderable, ILoadable, ILoader इत्यादि। स्पष्टता के लिए, मैंने इनमें से प्रत्येक "व्यवहार" को अलग-अलग आंशिक वर्गों जैसे "Entity.IUpdateable.cs", "Entity.IRenderable.cs" में अलग कर दिया और यथासंभव फ़ील्ड और विधियों को स्वतंत्र रखने का प्रयास किया।

व्यवहार पैटर्न को परिभाषित करने के लिए इंटरफेस का उपयोग करने का दृष्टिकोण भी मेरे साथ सहमत है क्योंकि जेनरिक, बाधाएं और सह (ntra) प्रकार प्रकार पैरामीटर एक साथ बहुत अच्छी तरह से काम करते हैं।

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


क्या आप किसी भी समस्या में भाग गए या किसी भी क्षण में आपको इस तरह के डिजाइन पर पछतावा हो रहा था और वास्तव में इच्छित चीजों को प्राप्त करने के लिए अपने स्वयं के कोड से लड़ना पड़ा? उदाहरण के लिए अचानक यह पता चला कि आपको इतने व्यवहार कार्यान्वयन बनाने की आवश्यकता है कि यह सिर्फ समझ में न आए और आप चाहते हैं कि आप पुराने विषय पर चिपके रहें "बेस क्लास को लाखों वर्चुअल्स के साथ बनाएं और विरासत में मिला और इससे नरक को खत्म करें"?
ग्रापुलेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.