我听说很多VBA缺少继承。我做了一些解决方法,现在在我看来,这正是继承的作用。我离pro =)很远,并且可能缺少一些东西。因此,我非常感谢您对可能存在的不利因素的想法。
当我发现仍然可以完全实现接口类中的功能(不仅是签名)时,我感到非常惊讶,这使我想到了以下内容。我看到有些人在合成的帮助下做了类似的事情,但是他们在界面中仅使用了签名。
IBird-类
Public Sub SayFromInterface()
Debug.Print "Tweet from IBird"
End Sub
Public Sub SayFromInstance()
End Sub
Run Code Online (Sandbox Code Playgroud)
乌鸦级
Implements IBird
Private pBird As IBird
Private Sub Class_Initialize()
Set pBird = New IBird
End Sub
'let you use already implemented code from "abstract class", to avoid
'duplicating your code, which is the main point of inheritance
'in my opinion
Public Sub IBird_SayFromInterface()
pBird.SayFromInterface
End Sub
'you can override the IBird function (common use)
Public Sub IBird_SayFromInstance()
Debug.Print "Tweet from Crow"
End Sub
Run Code Online (Sandbox Code Playgroud)
测试-模块
Sub testIBird()
Dim Bird As IBird
Set Bird = New Crow
Bird.SayFromInterface
Bird.SayFromInstance
Debug.Print TypeName(Bird)
Debug.Print TypeOf Bird Is IBird
End Sub
Run Code Online (Sandbox Code Playgroud)
输出:
Tweet from IBird
Tweet from Crow
Crow
True
Run Code Online (Sandbox Code Playgroud)
那是合成,不是继承-是的,有了合成,您就可以从本质上模拟继承。而且,如果该类实现了封装对象的接口,那么事情将开始看起来像某种装饰器模式。
除非您在中没有任何实现代码IBird。接口应该是纯抽象的。创建一个New应该是接口的实例,使该类不再是接口:现在,它只是另一个类,它公开了任何其他类都可以实现的默认接口,并且I前缀变得相当混乱:
Run Code Online (Sandbox Code Playgroud)Set pBird = New IBird
这是相当奇怪的是,客户端代码现在需要怀疑他们是否希望该鸟啁啾FromInstance或FromInterface-这些都是非常“元”标识,使事情不工作,如继承。
如果我们在Crow : Bird哪里Bird有此实现的地方IBird.Chirp:
Set pBird = New IBird
Run Code Online (Sandbox Code Playgroud)
...然后Crow有这个:
public virtual string Chirp() => "Chirp!";
Run Code Online (Sandbox Code Playgroud)
然后调用哪种方法取决于运行时类型是什么-这应该很明显:
public override string Chirp() => "Craaaw!";
Run Code Online (Sandbox Code Playgroud)
但是,请看一个接收IBird参数的方法:
IBird bird1 = new Bird();
bird1.Chirp(); // "Chirp!"
IBird bird2 = new Crow();
bird2.Chirp(); // "Craaaw!"
Run Code Online (Sandbox Code Playgroud)
如果bird为Bird,则显示“ Chirp!”;如果bird为a Crow,则显示“ Craaaw!”:开始运行的方法是派生程度最高的替代,它不一定在派生性最大的类型上定义。
继承将允许GiantCrow : Crow继承Chirp方法,Crow而不必覆盖它。而这就是你不能用VBA类模拟:你是被迫写的等价...
public void DoSomething(IBird bird)
{
Debug.Print(bird.Chirp());
}
Run Code Online (Sandbox Code Playgroud)
...这在技术上是多余的,并且如果您每次都必须这样做,只是为了使“基本”成员在默认界面上可见,则会变得非常重复。
实际上,我们没有继承基本成员,而是包装了对封装对象的调用。该装饰图案正是这么做的,并为您提供延伸的VBA类或接口的非侵入性的方式。
装饰器实现其扩展的接口,并封装该类型的私有实例。因此,基本上使用装饰器,“乌鸦继承层次”设置如下所示:
Dim bird As IBird
Set bird = Crow.Create(New BaseBird)
Run Code Online (Sandbox Code Playgroud)
一个也许更合适的装饰器模式示例可能是:
Dim repository As IRepository
Set repository = LoggingRepository.Create(BirdRepository.Create(connectionString), New DebugLogger)
Run Code Online (Sandbox Code Playgroud)
凡BirdRepository负责抽象与一些数据库操作Birds表(BirdRepository工具IRepository),并在那里LoggingRepository是一个装饰是还器具IRepository,还包装了一个IRepository实例(在这种情况下BirdRepository),以增加自己的功能-这可能看起来像这样的:
'@PredeclaredId
Implements IRepository
Private loggerInternal As ILogger
Private wrappedInternal As IRepository
Public Function Create(ByVal internal As IRepository, ByVal logger As ILogger) As IRepository
Dim result As LoggingRepository
Set result.Wrapped = internal
Set result.Log = logger
Set Create = result
End Function
Public Property Get Wrapped() As IRepository
Set Wrapped = wrappedInternal
End Property
Public Property Set Wrapped(ByVal value As IRepository)
If Not wrappedInternal Is Nothing Then Err.Raise 5, TypeName(Me), "Instance is already initialized."
Set wrappedInternal = value
End Property
Public Property Get Log() As ILogger
Set Log = loggerInternal
End Property
Public Property Set Log(ByVal value As ILogger)
If Not loggerInternal Is Nothing Then Err.Raise 5, TypeName(Me), "Instance is already initialized."
Set loggerInternal = value
End Property
Private Function IRepository_SelectAll() As Object
Log.Info "Starting IRepository.SelectAll"
Dim t As Double
t = Timer
Set IRepository_SelectAll = wrappedInternal.SelectAll
Log.Info "IRepository.SelectAll completed in " & Timer - t & " seconds."
End Function
Private Sub IRepository_Delete(ByVal id As Long)
Log.Info "Starting IRepository.Delete(" & id & ")"
Dim t As Double
t = Timer
wrappedInternal.Delete id
Log.Info "IRepository.Delete completed in " & Timer - t & " seconds."
End Sub
Private Sub IRepository_Save(ByVal entity As Object)
'...
wrappedInternal.Save entity
'...
End Sub
'...
Run Code Online (Sandbox Code Playgroud)
被赋予IRepository对象的方法不能(绝对不应该)知道给它的方法是普通的BirdRepository,LoggingRepository包装a的BirdRepository还是FakeRepository封装a Collection而不是访问数据库表的a-这种多态性就是重点。
这是在不使用继承的情况下扩展类型的一种方法,即VBA可以绝对利用而不会过多地破坏模式。但这不是继承。
| 归档时间: |
|
| 查看次数: |
118 次 |
| 最近记录: |