封装
封装隐藏了客户端代码的实现细节
该处理将对 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
属性封装了复选框’state; 客户端代码不需要知道有一个复选框,只是有一个布尔值的设置。通过封装 Boolean
值,我们在复选框周围添加了一个抽象层。
使用接口来强制实现不变性
让我们通过将表单的模型**封装在专用的类模块中来进一步推进。但是如果我们为 UserName
和 Timestamp
制作了一个 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
请注意,Timestamp
和 UserName
属性仅显示 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
接口访问时只读的属性值,这里是 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
作为只读属性公开,永远不能重新分配(只要代码是针对接口编写的)。