खोज…


मतिहीनता

अमूर्तता का स्तर चीजों को विभाजित करने के लिए निर्धारित करने में मदद करता है।

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

Public Sub DoSomething()
    With New SomeForm
        Set .Model = CreateViewModel
        .Show vbModal            
        If .IsCancelled Then Exit Sub
        ProcessUserData .Model
    End With
End Sub

DoSomething प्रक्रिया में एक उच्च अमूर्त स्तर होता है : हम बता सकते हैं कि यह एक फॉर्म प्रदर्शित कर रहा है और कुछ मॉडल बना रहा है, और उस ऑब्जेक्ट को कुछ ProcessUserData प्रक्रिया से गुजर रहा है जो जानता है कि इसके साथ क्या करना है - मॉडल कैसे बनाया जाता है, यह एक अन्य प्रक्रिया का काम है:

Private Function CreateViewModel() As ISomeModel
    Dim result As ISomeModel
    Set result = SomeModel.Create(Now, Environ$("UserName"))
    result.AvailableItems = GetAvailableItems
    Set CreateViewModel = result
End Function

CreateViewModel फ़ंक्शन केवल कुछ ISomeModel उदाहरण बनाने के लिए ज़िम्मेदार है। उस जिम्मेदारी का एक हिस्सा उपलब्ध वस्तुओं का एक सरणी प्राप्त करना है - इन वस्तुओं को कैसे प्राप्त किया जाता है यह एक कार्यान्वयन विवरण है जो GetAvailableItems प्रक्रिया के पीछे सार है:

Private Function GetAvailableItems() As Variant
    GetAvailableItems = DataSheet.Names("AvailableItems").RefersToRange
End Function

यहां प्रक्रिया DataSheet वर्कशीट पर नामांकित सीमा से उपलब्ध मानों को पढ़ रही है। यह सिर्फ एक डेटाबेस से उन्हें पढ़ सकता है, या मूल्यों को हार्ड-कोडित किया जा सकता है: यह एक कार्यान्वयन विवरण है जो उच्चतर अमूर्त स्तरों में से किसी के लिए चिंता का विषय नहीं है।

encapsulation

एन्कैप्सुलेशन क्लाइंट कोड से कार्यान्वयन विवरण छिपाता है।

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

जब चेकबॉक्स मान बदलता है, तो हैंडलर एक निजी क्षेत्र का सदस्य प्रदान करता है:

Private Type TView
    IsCancelled As Boolean
    SomeOtherSetting As Boolean
    'other properties skipped for brievety
End Type
Private this As TView

'...

Private Sub SomeOtherSettingInput_Change()
    this.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub

और जब क्लाइंट कोड उस मूल्य को पढ़ना चाहता है, तो उसे एक चेकबॉक्स के बारे में चिंता करने की आवश्यकता नहीं है - इसके बजाय यह केवल कुछ SomeOtherSetting संपत्ति का उपयोग करता है:

Public Property Get SomeOtherSetting() As Boolean
    SomeOtherSetting = this.SomeOtherSetting
End Property

SomeOtherSetting गुण चेकबॉक्स स्थिति को SomeOtherSetting करता है; क्लाइंट कोड को यह जानने की जरूरत नहीं है कि इसमें एक चेकबॉक्स शामिल है, केवल यह कि बूलियन मान के साथ एक सेटिंग है। द्वारा encapsulating Boolean मूल्य, हम चेकबॉक्स के चारों ओर एक अमूर्त स्तर जोड़ा है।


अपरिवर्तनशीलता को लागू करने के लिए इंटरफेस का उपयोग करना

आइए धक्का देते हैं कि एक समर्पित वर्ग मॉड्यूल में फॉर्म के मॉडल को संलग्न करके एक कदम आगे। लेकिन अगर हमने UserName और Timestamp लिए एक Public Property बनाई है, तो हमें Public Property को UserName करने वाले Property Let एक्सेसर्स को उजागर करना होगा, और हम क्लाइंट कोड को इन मूल्यों को सेट करने के बाद बदलने की क्षमता नहीं रखना चाहते हैं।

Abstraction उदाहरण में CreateViewModel फ़ंक्शन एक ISomeModel श्रेणी देता है: यह हमारा इंटरफ़ेस है , और यह इस तरह दिखता है:

Option Explicit

Public Property Get Timestamp() As Date
End Property

Public Property Get UserName() As String
End Property

Public Property Get AvailableItems() As Variant
End Property

Public Property Let AvailableItems(ByRef value As Variant)
End Property

Public Property Get SomeSetting() As String
End Property

Public Property Let SomeSetting(ByVal value As String)
End Property

Public Property Get SomeOtherSetting() As Boolean
End Property

Public Property Let SomeOtherSetting(ByVal value As Boolean)
End Property

नोटिस Timestamp और UserName गुण केवल एक Property Get UserName बेनकाब करते हैं। अब SomeModel वर्ग उस इंटरफ़ेस को लागू कर सकता है:

Option Explicit
Implements ISomeModel

Private Type TModel
    Timestamp As Date
    UserName As String
    SomeSetting As String
    SomeOtherSetting As Boolean
    AvailableItems As Variant
End Type
Private this As TModel

Private Property Get ISomeModel_Timestamp() As Date
    ISomeModel_Timestamp = this.Timestamp
End Property

Private Property Get ISomeModel_UserName() As String
    ISomeModel_UserName = this.UserName
End Property

Private Property Get ISomeModel_AvailableItems() As Variant
    ISomeModel_AvailableItems = this.AvailableItems
End Property

Private Property Let ISomeModel_AvailableItems(ByRef value As Variant)
    this.AvailableItems = value
End Property

Private Property Get ISomeModel_SomeSetting() As String
    ISomeModel_SomeSetting = this.SomeSetting
End Property

Private Property Let ISomeModel_SomeSetting(ByVal value As String)
    this.SomeSetting = value
End Property

Private Property Get ISomeModel_SomeOtherSetting() As Boolean
    ISomeModel_SomeOtherSetting = this.SomeOtherSetting
End Property

Private Property Let ISomeModel_SomeOtherSetting(ByVal value As Boolean)
    this.SomeOtherSetting = value
End Property

Public Property Get Timestamp() As Date
    Timestamp = this.Timestamp
End Property

Public Property Let Timestamp(ByVal value As Date)
    this.Timestamp = value
End Property

Public Property Get UserName() As String
    UserName = this.UserName
End Property

Public Property Let UserName(ByVal value As String)
    this.UserName = value
End Property

Public Property Get AvailableItems() As Variant
    AvailableItems = this.AvailableItems
End Property

Public Property Let AvailableItems(ByRef value As Variant)
    this.AvailableItems = value
End Property

Public Property Get SomeSetting() As String
    SomeSetting = this.SomeSetting
End Property

Public Property Let SomeSetting(ByVal value As String)
    this.SomeSetting = value
End Property

Public Property Get SomeOtherSetting() As Boolean
    SomeOtherSetting = this.SomeOtherSetting
End Property

Public Property Let SomeOtherSetting(ByVal value As Boolean)
    this.SomeOtherSetting = value
End Property

इंटरफ़ेस सदस्य सभी Private , और कोड को संकलित करने के लिए इंटरफ़ेस के सभी सदस्यों को लागू किया जाना चाहिए। Public सदस्य इंटरफ़ेस का हिस्सा नहीं हैं, और इसलिए ISomeModel इंटरफ़ेस के खिलाफ लिखे गए कोड के संपर्क में नहीं हैं।


एक निर्माता का अनुकरण करने के लिए एक फैक्ट्री विधि का उपयोग करना

VB_PredeclaredId विशेषता का उपयोग करते हुए, हम SomeModel वर्ग को एक डिफ़ॉल्ट उदाहरण बना सकते हैं, और एक फ़ंक्शन लिख सकते हैं जो एक प्रकार-स्तर (VB.NET में Shared , C # में static ) सदस्य की तरह काम करता है जिसे ग्राहक कोड पहले बनाने की आवश्यकता के बिना कॉल कर सकता है। एक उदाहरण, जैसे हमने यहाँ किया:

Private Function CreateViewModel() As ISomeModel
    Dim result As ISomeModel
    Set result = SomeModel.Create(Now, Environ$("UserName"))
    result.AvailableItems = GetAvailableItems
    Set CreateViewModel = result
End Function

यह फैक्ट्री विधि संपत्ति मूल्यों को पढ़ती है जो केवल ISomeModel इंटरफ़ेस से एक्सेस किए जाते हैं, यहां Timestamp और UserName :

Public Function Create(ByVal pTimeStamp As Date, ByVal pUserName As String) As ISomeModel
    With New SomeModel
        .Timestamp = pTimeStamp
        .UserName = pUserName
        Set Create = .Self
    End With
End Function

Public Property Get Self() As ISomeModel
    Set Self = Me
End Property

और अब हम ISomeModel इंटरफ़ेस के खिलाफ कोड कर सकते हैं, जो Timestamp और UserName को केवल-पढ़ने योग्य गुणों के रूप में उजागर करता है जिन्हें कभी भी पुन: असाइन नहीं किया जा सकता है (जब तक कोड इंटरफ़ेस के खिलाफ लिखा गया है)।

बहुरूपता

बहुरूपता विभिन्न अंतर्निहित कार्यान्वयन के लिए एक ही इंटरफ़ेस प्रस्तुत करने की क्षमता है।

इंटरफेस को लागू करने की क्षमता पूरी तरह से यूआई से या डेटाबेस से या इस या उस वर्कशीट से एप्लिकेशन लॉजिक को डिकोड करने की अनुमति देती है।

मान लें कि आपके पास एक ISomeView इंटरफ़ेस है जो फ़ॉर्म स्वयं लागू करता है:

Option Explicit

Public Property Get IsCancelled() As Boolean
End Property

Public Property Get Model() As ISomeModel
End Property

Public Property Set Model(ByVal value As ISomeModel)
End Property

Public Sub Show()
End Sub

प्रपत्र का कोड-पीछे ऐसा दिख सकता है:

Option Explicit 
Implements ISomeView

Private Type TView
    IsCancelled As Boolean
    Model As ISomeModel
End Type
Private this As TView

Private Property Get ISomeView_IsCancelled() As Boolean
    ISomeView_IsCancelled = this.IsCancelled
End Property

Private Property Get ISomeView_Model() As ISomeModel
    Set ISomeView_Model = this.Model
End Property

Private Property Set ISomeView_Model(ByVal value As ISomeModel)
    Set this.Model = value
End Property

Private Sub ISomeView_Show()
    Me.Show vbModal
End Sub

Private Sub SomeOtherSettingInput_Change()
    this.Model.SomeOtherSetting = CBool(SomeOtherSettingInput.Value)
End Sub

'...other event handlers...

Private Sub OkButton_Click()
    Me.Hide
End Sub

Private Sub CancelButton_Click()
    this.IsCancelled = True
    Me.Hide
End Sub

Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
    If CloseMode = VbQueryClose.vbFormControlMenu Then
        Cancel = True
        this.IsCancelled = True
        Me.Hide
    End If
End Sub

लेकिन फिर, एक और वर्ग मॉड्यूल बनाने से कोई मना नहीं करता है जो उपयोगकर्ता प्रपत्र के बिना ISomeView इंटरफ़ेस को लागू करता है - यह एक SomeViewMock वर्ग हो सकता है:

Option Explicit
Implements ISomeView

Private Type TView
    IsCancelled As Boolean
    Model As ISomeModel
End Type
Private this As TView

Public Property Get IsCancelled() As Boolean
    IsCancelled = this.IsCancelled
End Property

Public Property Let IsCancelled(ByVal value As Boolean)
    this.IsCancelled = value
End Property

Private Property Get ISomeView_IsCancelled() As Boolean
    ISomeView_IsCancelled = this.IsCancelled
End Property

Private Property Get ISomeView_Model() As ISomeModel
    Set ISomeView_Model = this.Model
End Property

Private Property Set ISomeView_Model(ByVal value As ISomeModel)
    Set this.Model = value
End Property

Private Sub ISomeView_Show()
    'do nothing
End Sub

और अब हम उस कोड को बदल सकते हैं जो एक UserForm साथ काम करता है और इसे ISomeView इंटरफ़ेस से काम करता है, जैसे कि इसे ISomeView करने के बजाय इसे एक पैरामीटर के रूप में रूप देकर:

Public Sub DoSomething(ByVal view As ISomeView)
    With view
        Set .Model = CreateViewModel
        .Show
        If .IsCancelled Then Exit Sub
        ProcessUserData .Model
    End With
End Sub

क्योंकि DoSomething विधि एक इंटरफेस (यानी एक अमूर्त) और नहीं एक ठोस वर्ग (जैसे एक विशिष्ट पर निर्भर करता है UserForm ), हम एक स्वचालित इकाई परीक्षण लिख सकते हैं कि यह सुनिश्चित करता है कि ProcessUserData निष्पादित नहीं है जब view.IsCancelled है True , बनाने के द्वारा हमारे परीक्षण एक बनाने SomeViewMock उदाहरण है, इसकी स्थापना के IsCancelled को संपत्ति True , और करने के लिए इसे पारित DoSomething


परीक्षण योग्य कोड सार पर निर्भर करता है

VBA में राइटिंग यूनिट टेस्ट किए जा सकते हैं, वहाँ ऐड-इन्स हैं जो इसे IDE में एकीकृत करते हैं। लेकिन जब कोड को किसी वर्कशीट, डेटाबेस, फॉर्म, या फाइल सिस्टम के साथ कस कर जोड़ दिया जाता है, तो यूनिट टेस्ट के लिए वास्तविक वर्कशीट, डेटाबेस, फॉर्म या फाइल सिस्टम की आवश्यकता होती है - और ये निर्भरताएँ नई आउट-ऑफ-कंट्रोल विफलता हैं परीक्षण योग्य कोड को अलग करना चाहिए, ताकि यूनिट परीक्षणों को वास्तविक वर्कशीट, डेटाबेस, फॉर्म या फाइल सिस्टम की आवश्यकता हो।

इंटरफेस के खिलाफ कोड लिखकर, एक तरह से टेस्ट कोड को स्टब / मॉक SomeViewMock (जैसे कि SomeViewMock उदाहरण) को इंजेक्ट करने की अनुमति देता है, आप एक "नियंत्रित वातावरण" में परीक्षण लिख सकते हैं, और अनुकरण कर सकते हैं जब 42 में से हर एक संभव होता है। फ़ॉर्म के डेटा पर उपयोगकर्ता के इंटरैक्शन की अनुमति, एक बार भी एक फॉर्म प्रदर्शित करने और मैन्युअल रूप से नियंत्रण पर क्लिक किए बिना।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow