수색…


추출

추상화 레벨은 상황을 분할 할시기를 결정하는 데 도움이됩니다.

추상화는 점차 세부적인 코드로 기능을 구현함으로써 성취됩니다. 매크로의 시작점은 높은 추상화 수준 의 작은 프로 시저로, 상황을 한 눈에 파악하기 쉽습니다.

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 시트 워크 시트의 명명 된 범위에서 사용 가능한 값을 읽는 것입니다. 데이터베이스에서 값을 읽는 것만으로도 값을 하드 코딩 할 수 있습니다. 더 높은 추상화 수준에 대해서는 아무런 관심도없는 구현 세부 사항 입니다.

캡슐화

캡슐화는 클라이언트 코드에서 구현 세부 사항을 숨 깁니다.

Handling 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 때 체크 박스에 대해 걱정할 필요가 없습니다. 대신 단순히 SomeOtherSetting 속성을 사용합니다 :

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

SomeOtherSetting 속성은 확인란의 상태를 캡슐화 합니다. 클라이언트 코드에는 관련된 체크 박스가 있다는 것을 알 필요가 없으며 부울 값이있는 설정 만 있습니다. Boolean 값을 캡슐화 하여 체크 상자 주위에 추상화 레이어를 추가했습니다.


인터페이스를 사용하여 불변성 강화

폼의 모델 을 전용 클래스 모듈에 캡슐화 하여 한 걸음 더 나아가 보겠습니다. 그러나 UserNameTimestamp 대해 Public Property 을 만든 경우 Property Let 접근자를 노출시켜 속성을 변경할 수있게해야하며 클라이언트 코드가 설정 한 후에이 값을 변경할 수있는 기능을 원하지 않습니다.

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

알림 TimestampUserName 속성은 Property Get 접근 자만 노출합니다. 이제 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 인터페이스에서 액세스 할 때 읽기 전용 인 속성 값을 여기에 TimestampUserName 할당합니다.

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 인터페이스에 대해 코드를 작성할 수 있습니다.이 인터페이스는 TimestampUserName 을 코드 재 지정이 ISomeModel 읽기 전용 속성으로 노출합니다 (코드가 인터페이스에 대해 작성된 경우).

다형성

다형성은 서로 다른 기본 구현에 대해 동일한 인터페이스를 제공 할 수있는 기능입니다.

인터페이스를 구현하는 기능을 통해 응용 프로그램 논리를 UI, 데이터베이스 또는이 워크 시트에서 완전히 분리 할 수 ​​있습니다.

양식 자체에서 구현하는 ISomeView 인터페이스가 있다고 가정 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 인터페이스를 구현하는 또 다른 클래스 모듈을 만드는 것을 금지 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 인터페이스에서 작동하도록 만들 수 있습니다.

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 )가 아닌 인터페이스 (즉, 추상화 )에 의존하기 때문에 view.IsCancelledTrue 일 때 ProcessUserData 가 실행되지 않도록하는 자동 단위 테스트를 작성할 수 있습니다. 테스트를 통해 SomeViewMock 인스턴스를 만들고 IsCancelled 속성을 True 설정 한 IsCancelled DoSomething 전달합니다.


테스트 가능한 코드는 추상화에 따라 다릅니다.

VBA에서 단위 테스트를 작성하면 IDE에 통합하는 추가 기능이 있습니다. 그러나 코드가 워크 시트, 데이터베이스, 폼 또는 파일 시스템과 밀접하게 결합 되면 단위 테스트는 실제 워크 시트, 데이터베이스, 폼 또는 파일 시스템을 필요로하기 시작합니다. 이러한 종속성 은 새로운 제어 불능 실패입니다 단위 테스트에서 실제 워크 시트, 데이터베이스, 폼 또는 파일 시스템을 필요로 하지 않도록 테스트 가능한 코드를 분리해야합니다.

테스트 코드가 스텁 / 모의 구현물 (예 : 위의 SomeViewMock 예제)을 삽입 할 수 있도록 인터페이스에 대해 코드를 작성하면 "제어 된 환경"에서 테스트를 작성하고 가능한 모든 가능한 경우에 어떤 일이 발생하는지 시뮬레이션 할 수 있습니다 양식을 표시하고 양식 컨트롤을 수동으로 클릭하지 않고도 양식의 데이터에 대한 사용자 상호 작용의 순열



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow