VBA是一种面向对象的语言吗?它支持多态性吗?
VBA是一种面向对象的语言吗?它支持多态性吗?
我实际上正在开展我的第一个VBA项目。 (来自C ++)
我想通过实现类和多态性来改进一个用于Microsoft Excel工作簿的现有VBA项目。
我的问题是:
1 - 我阅读了很多解释VBA不是面向对象编程(OOP)语言且不支持多态性的文章/论坛。
其中一些提出了使用关键字Implements的解决方法。
2 - 我还发现了一些网页,比如这个网页,它解释了如何在VBA中使用Inherits,Overrides,Overridable,MustOverrides等关键字进行OOP和多态性。
所以我的问题是:
VBA是一种面向对象编程语言,并且它支持多态性吗?
简短的回答是不和不。
VBA是基于对象的,允许您定义类并创建对象实例,但缺乏通常与完整的OOP语言相关的功能,例如:
- 封装和抽象:VBA在一定程度上提供了这个功能。类可以保持私有,定义公共接口,但是类中没有构造函数的提供。类有一个
Class_Inititalize
事件可以做一些构造,但无法传递参数。传递参数需要一个公共工厂函数,仍需要解决创建构造函数样式设计模式的问题。 - 继承:在VBA中实际上不存在,但可以几乎复制。
- 多态性:可以通过界面(使用
Implements
)在一定程度上实现,尽管不存在函数重载的能力(例如),每个“重载”实际上都需要一个独特的函数名称。您可以通过将对象作为函数或子例程的唯一参数传递,并根据属性值的变化来改变过程来解决此问题。
因此,尽管您可以在一定程度上使用对象,而且MS Office应用程序是基于对象模型构建的,但VBA并不是真正的面向对象语言。无法实现您在C++中熟悉的多态性。
OOP建立在4个“支柱”上:
-
抽象 - 通过在类模块中定义对象,可以轻松地抽象逻辑和概念。严格来说,使用有意义的标识符并将过程代码提取到方法(类成员)中也可以实现抽象。
这是一个使用VBA编写的过程的示例,说明了抽象:
Public Sub Test(ByVal checkin As Date, ByVal checkout As Date, ByVal custType As CustomerType) Dim finder As New HotelFinder InitializeHotels finder Debug.Print finder.FindCheapestHotel(checkin, checkout, custType) End Sub
很容易一眼看出这个
Test
过程的作用,因为抽象级别很高: 实现细节被抽象成更专业的对象和方法。 -
封装 - 类可以通过属性公开私有字段;类可以被设置为
PublicNotCreatable
,有效地将类型暴露给其他VBA项目 - 并通过一点点努力 (导出类模块,用你喜欢的文本编辑器打开它,手动编辑类属性,然后重新导入模块),你可以实现实际的只读类型。没有参数化构造函数这一事实是无关紧要的 - 只需编写一个接受所有所需参数并返回实例的工厂方法即可。这是COM,而COM喜欢工厂。这是从以上片段中的
HotelFinder
类演示的,封装了一个Collection
对象并仅通过一个Property Get
访问器公开它 - 在这个类外部的代码根本无法设置此引用,它被封装:Private Type TFinder Hotels As Collection End Type Private this As TFinder Public Property Get Hotels() As Collection Set Hotels = this.Hotels End Property Private Sub Class_Initialize() Set this.Hotels = New Collection End Sub Private Sub Class_Terminate() Set this.Hotels = Nothing End Sub
-
多态性 -
Implements
可以让你实现抽象接口(和具体类),然后你可以编写针对ISomething
抽象的代码,这个抽象可以完全是Foo
或Bar
(如果Foo
和Bar
都实现了ISomething
),而所有代码只需要查看ISomething
。方法重载是VBA缺少的语言特性,但重载与多态性无关,多态性是呈现不同基础形式(数据类型)的相同接口的能力。这是应用多态性的示例 -
LogManager.Register
方法可以处理实现ILogger
接口的任何对象;这里的一个DebugLogger
和FileLogger
,是该接口的两个截然不同的实现,正在注册;当稍后调用LogManager.Log(ErrorLevel, Err.Description)
时,两个实现将各自执行自己的操作;DebugLogger
将输出到立即窗口,FileLogger
将在指定的日志文件中写入一个条目:LogManager.Register DebugLogger.Create("MyLogger", DebugLevel) LogManager.Register Filelogger.Create("TestLogger", ErrorLevel, "C:\Dev\VBA\log.txt")
-
继承 - VBA不允许您从另一个类型派生出一个类型:不支持继承。
现在的问题是,一个不支持继承的语言可以被称为"面向对象"吗?结果证明,组合往往比继承更可取,后者有许多注意事项。而VBA将让您尽情进行对象组合。
VBA是一种面向对象的语言吗?
考虑到所有缺少的是继承,以及组合优于继承,我很想回答"是的"。我以前写过充分的OOP VBA代码(Model-View-Presenter with Unit-of-Work and Repository,有人吗?),我不会在支持继承的"真正的OOP"语言中写任何不同的代码。
下面是一些100% VBA的示例:
- Model-View-ViewModel架构和示例(概念验证)
- 带有Model-View-Controller(MVC)架构的完整的OOP Battleship游戏
- 可重用的进度指示器
- Model-View-Presenter模式
- 带有Repository模式的UnitOfWork
- 多态日志记录器
- Automagic Unit Testing框架
最后一个链接中的代码最终被移植到C#,并迅速发展成为VBA IDE的一款COM插件,该插件为您提供了重构,更好的导航,代码检查和其他工具。
VBA仅限于您的想象力。