VBA继承模式

man*_*lan 12 vba

VBA是基于COM的,COM不进行继承.但我想我可能有一个模式,它近似于它的某些方面:

Animal.cls

Public Sub Speak() 
    Err.Raise 418, , "Not supported" 
End Sub 
Run Code Online (Sandbox Code Playgroud)

Dog.cls

Implements Animal 

Private mBase As Animal 

Private Sub Class_Initialize() 
  Set mBase = New Animal 
End Sub 

Private Sub Animal_Speak() 
   Me.Speak 
End Sub 

Public Sub Speak() 
   MsgBox "Woof!" 
End Sub 

Public Property Get Base() As Animal 
    Set Base = mBase 
End Property 
Run Code Online (Sandbox Code Playgroud)

Test.bas

Sub Test() 
    Dim animal As animal: Set animal = New dog 
    Dim dog As dog: Set dog = New dog 
    Dim object As Object: Set object = New dog 

    dog.Speak      ' direct      : Woof! 
    animal.Speak   ' polymorphic : Woof! 
    object.Speak   ' late-bound  : Woof! 
    dog.Base.Speak ' fake upcast : Err 418 
End Sub
Run Code Online (Sandbox Code Playgroud)

因此,在Dog.cls中实现的接口成员Animal_Speak(它是私有的,以防止它被直接调用)将调用转发给公共Speak方法,该方法可以将其委托给Animal.cls中的等效子(或"继承")或用其他东西替换它('覆盖').

此外,如果调用者确实需要基本行为("upcast"),则会暴露Dog.cls中的Base属性.

(引号中的术语,因为它们只是近似值).

所以,我的问题是:

  1. 这是一种已知的模式,如果是这样,它是否流行?
  2. 有什么缺点吗?

Mat*_*don 16

您正在实现的模式是一种组合形式,它是继承的常用代理,即使在支持类继承的语言中也是如此.你看到继承有它的缺点,并且组合通常比它更受欢迎.

组合不需要接口.实际上,每当您在对象中封装对象的实例,然后暴露内部对象的一些(或全部)成员时,您就使用了合成.

在您的具体示例中,您正在使用"抽象类"(Animal- 接口)进行编写,这没有多大意义,因为接口并不是要直接实例化,如下所示:

Set mBase = New Animal
Run Code Online (Sandbox Code Playgroud)

在真正的代码,你可以有一个IRepository接口,ProductSqlRepository实现它(然后SupplierSqlRepository再一个OrderSqlRepository,等等),你可以编写一些的实现SqlRepository类暴露了通用的功能,所有的实现使用,各自在自己的具体方式:同时客户端代码只需要知道/关心IRepository.


您正在通过接口继承发现VBA 中多态性的可能性,这与类继承不同.

使用类继承,您可以在派生类中拥有virtualabstract至方法.override

使用.NET风格的接口继承,您可以拥有一个扩展另一个接口的接口,实现类型可以实现该接口以满足编译器 - 它公开了它所扩展的所有接口的成员.

使用VBA风格的接口继承,您将获得一个可以实现接口的类.或者两个.或者三个.或者更多....... COM类型的方式.

而那.​​.....已经非常棒了.

它被称为面向对象编程 --OOP包含4件事:

  • 抽象化
  • 封装
  • 继承(悲伤的VBA)
  • 多态性

它是很多编程语言中流行的范例,例如Java和C#.理想的OOP代码是SOLID,松散耦合的代码,可以轻松进行单元测试.SOLID原则指导了许多OOP设计:

  • [S]单一的责任原则
  • [O]笔/封闭原则
  • [L] iskov替代原则
  • [I]接口隔离原则
  • [D]依赖性倒置原则

尽管缺乏继承功能,VBA仍然可以尊重这些OOP原则,同时拥抱其无构造的COM特性.代码审查的可扩展日志记录,以及实现DatabaseLogger的后续帖子,对它进行了非常有力的演示.

但即使不使用接口,在OOP中思考也可以封装任何功能,并以可重用组件的方式编写它.就像这个可重用的进度指示器一样,它说明了如何离开运行show的UI(UserForm或工作表)代码隐藏,使UI成为应用程序逻辑中的I/O设备.

通过VBA学习OOP,您将雕刻您的思维过程,开始从程序范式到面向对象代码的奇迹之旅.一旦掌握了这一点,你就会希望将你的经验扩展到成熟的类继承,并发现代理和匿名函数,甚至可能会研究功能编程范例,这是另一种完全不同的思考方式.代码,像OOP一样是程序性的.

不幸的是,当VB6风靡一时时,VBA IDE,光荣的VBE,最后更新了,并没有太多OOP鼓励功能.甚至可以说VBE积极讨厌OOP:

  • Project Explorer的唯一文件夹是模块类型,因此具有多个类的项目很快就会成为导航的噩梦.
  • 没有"去实现"功能来轻松定位接口的实现.
  • 没有重构工具.
  • 没有单元测试.
  • 没有静态代码分析.

公平地说,单元测试和重构工具在1999年并不像今天那样普遍(AFAIK).尽管如此,VBA中OOP的缺点是IDE本身缺乏功能.

幸运的是,VBIDE具有可扩展性模型并支持加载项.因此,您可以获得Rubberduck并拥有所有这些功能,并在VBA中编写OOP代码,而不会经常遇到缺乏IDE功能的问题.

免责声明:我管理在GitHub上托管的Rubberduck开源项目.