gpt4 book ai didi

VBA继承

转载 作者:行者123 更新时间:2023-12-03 23:56:23 28 4
gpt4 key购买 nike

我听说 VBA 缺乏继承。我做了一些解决方法,现在在我看来,这正是继承所做的。我离 pro =) 很远,可能遗漏了一些东西。因此,我非常感谢您对可能存在的缺点的想法。

当我发现你仍然可以在一个接口(interface)类中实现一个功能的完整实现时,我感到非常惊讶(不仅仅是一个签名),这让我想到了下面的内容。我看到有些人在组合的帮助下做了类似的事情,但他们只在界面中使用了一个签名。

IBird - 类

Public Sub SayFromInterface()
Debug.Print "Tweet from IBird"
End Sub

Public Sub SayFromInstance()
End Sub

乌鸦级

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

测试 - 模块

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

输出:

Tweet from IBird
Tweet from Crow
Crow
True

最佳答案

那是组合,而不是继承 - 是的,通过组合,您基本上可以模拟继承。如果该类实现封装对象的接口(interface),那么事情开始看起来像某种装饰器模式。

除非您在IBird 中没有任何实现代码。接口(interface)应该是纯抽象的。制作一个应该是接口(interface)的 New 实例,使该类不再是接口(interface):现在它只是另一个类,暴露了任何其他类都可以实现的默认接口(interface),而 I 前缀变得相当困惑:

Set pBird = New IBird

很奇怪,客户端代码现在需要想知道他们是想让那只鸟鸣叫 FromInstance 还是 FromInterface - 这些是非常“元”的标识符,可以使事情 < em>不像继承一样工作。

如果我们有一个 Crow : Bird,其中 BirdIBird.Chirp 的实现:

public virtual string Chirp() => "Chirp!";

...然后 Crow 有这个:

public override string Chirp() => "Craaaw!";

然后调用哪个方法取决于运行时类型 - 这应该很明显:

IBird bird1 = new Bird();
bird1.Chirp(); // "Chirp!"

IBird bird2 = new Crow();
bird2.Chirp(); // "Craaaw!"

然而想象一个接收IBird参数的方法:

public void DoSomething(IBird bird)
{
Debug.Print(bird.Chirp());
}

如果 birdBird,它会打印“Chirp!”;如果 birdCrow,它会打印“Craaaw!”:要运行的方法是最派生的覆盖,不一定定义在最派生的类型

继承将允许 GiantCrow : CrowCrow 继承 Chirp 方法并且不一定覆盖它. 是您无法用 VBA 类模拟的:您被迫编写等同于...

public override string Chirp() => base.Chirp();

...这在技术上是多余的,如果您每次都必须这样做只是为了让“基本”成员在您的默认界面上可见,那么会变得非常重复。

我们实际上包装调用封装对象,而不是继承基成员。 装饰器 模式正是这样做的,它为您提供了一种扩展 VBA 类或接口(interface)的非侵入式方法。

装饰器实现它扩展的接口(interface),并封装该类型的私有(private)实例。所以基本上使用装饰器的“乌鸦继承层次结构”设置看起来像这样:

Dim bird As IBird
Set bird = Crow.Create(New BaseBird)

也许更合适的装饰器模式示例可能是:

Dim repository As IRepository
Set repository = LoggingRepository.Create(BirdRepository.Create(connectionString), New DebugLogger)

其中 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

'...

被赋予 IRepository 对象的方法不能(而且绝对不应该)知道它是否被赋予了一个普通的 BirdRepository,一个 LoggingRepository 包装一个 BirdRepository,或者一个 FakeRepository 封装一个 Collection 而不是访问数据库表 - 这种多态性是整点。

这是一种不使用继承来扩展类型的方法,VBA 绝对可以利用它而不会过多地破坏模式。但这不是继承。

关于VBA继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57641543/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com