VBA是一种面向对象编程语言吗?它支持多态吗?

54

我实际上正在处理我的第一个VBA项目。(来自C ++

我想通过实现类和多态性来改进一个已经存在的VBA项目,该项目由Microsoft Excel工作簿使用。

我的问题是:

1 - 我阅读了许多解释VBA不是面向对象编程(OOP)语言并且不支持多态性的文章/论坛。其中一些提出了使用关键字Implements的解决方法。

2 - 我还发现了一些网页,例如这个,它解释了如何使用InheritsOverridesOverridableMustOverrides等关键字在VBA中执行OOP和多态性。

所以我的问题是:

VBA是一个OOP语言吗?它是否支持多态性?


6
点2涉及VB,而不是VBA。在VBA中没有像"Inherits"、"Overrides"、"Overridable"、"MustOverrides"这样的关键字。 - mielk
好的,但我认为VBA是Visual Basic for Application的缩写。它不是相同的基础语言吗? - Axel Borja
7
Visual Basic for Applications(VBA)是一种面向事件、面向对象的编程语言,用于编写宏,可用于整个Office套件以及其他应用程序...这是stackoverflow的定义 :). 在此处可以找到关于在VBA中使用Implements的一些帖子:Here - Daniel Dušek
2
VBA很像Visual Studio版本6及更早版本中的VB。现在的VB是VB.NET。VB.NET中的许多内容在VBA中并不存在。 - MatthewD
1
这里有一个关于“实现”(Implments)的好例子:http://www.cpearson.com/excel/Implements.aspx - Daniel Dušek
显示剩余2条评论
2个回答

114

OOP坐落在四个“支柱”上:

  • check Abstraction - Abstracting logic and concepts can easily be done by defining objects in class modules. Strictly speaking, abstraction is also achieved by using meaningful identifiers and extracting procedural code into methods (class members).

    Here's an example of a procedure written in VBA that demonstrates abstraction:

     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
    

    It's easy to tell what this Test procedure does at a glance, because the abstraction level is very high: the implementation details are abstracted away into more specialized objects and methods.

  • check Encapsulation - Classes can have private fields exposed by properties; classes can be made PublicNotCreatable, effectively exposing types to other VBA projects - and with a little bit of effort (by exporting the class module, opening it in your favorite text editor, manually editing class attributes, and re-importing the module), you can achieve actual read-only types. The fact that there are no parameterized constructors is irrelevant - just write a factory method that takes all the parameters you like and return an instance. This is COM, and COM likes factories anyway.

    Here's an example of how the HotelFinder class from the above snippet encapsulates a Collection object and only exposes it through a Property Get accessor - code outside this class simply cannot Set this reference, it's encapsulated:

     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
    
  • check Polymorphism - Implements lets you implement abstract interfaces (and concrete classes, too), and then you can write code against an ISomething abstraction that can just as well be a Foo or a Bar (given Foo and Bar both implement ISomething) - and all the code ever needs to see is ISomething. Method overloading is a language feature that VBA lacks, but overloading has nothing to do with polymorphism, which is the ability to present the same interface for differing underlying forms (data types).

    Here's an example of applied polymorphism - the LogManager.Register method is happy to work with any object that implements the ILogger interface; here a DebugLogger and a FileLogger - two wildly different implementations of that interface, are being registered; when LogManager.Log(ErrorLevel, Err.Description) is invoked later, the two implementations will each do their own thing; DebugLogger will output to the immediate toolwindow, and FileLogger will write an entry into a specified log file:

     LogManager.Register DebugLogger.Create("MyLogger", DebugLevel)
     LogManager.Register Filelogger.Create("TestLogger", ErrorLevel, "C:\Dev\VBA\log.txt")
    
  • nope Inheritance - VBA does not let you derive a type from another: inheritance is not supported.


现在的问题是,一个不支持继承的语言是否有资格被称为“面向对象”?结果表明,组合通常比继承更可取,后者具有许多注意事项。VBA将允许您尽情地组合对象。
“VBA是一种面向对象的语言吗?”鉴于缺少继承,并且组合优于继承,我倾向于回答“是”。我以前编写过完整的OOP VBA代码(Model-View-Presenter with Unit-of-Work and Repository),我在支持继承的“真正的OOP”语言中也不会写得不同。
这里有几个例子,都是100%的VBA: 这个最后链接中的代码最终被移植到C#,并快速演变成为用于VBA IDE的COM插件,提供重构、更好的导航、代码检查和其他工具。
只要你愿意,VBA并不会限制你。

8
通过以与定义相矛盾的方式工作来实现相同目标,并不意味着你的方法与所定义的方法相同。如果面向对象编程(OOP)需要四个方面,而你只具备其中三个方面,再用一种非常不同且更加复杂的方式实现第四个方面的类似功能,也并不意味着你已经具备了所有四个方面。夸大其词以表达观点:我有一辆汽油车,如果我往里面加柴油然后推着它走,那并不意味着我有了一辆柴油车。 - stucharo
1
顺便说一下,我是你的Rubberduck插件的忠实粉丝。一个简单的VBA单元测试框架真是太好了,再加上一个实用的项目浏览器!我猜当你想要它成为OOP时,你转向了C# :P - stucharo
1
面向对象编程并不需要继承,只需要多态性。顺便感谢您对项目的赞美。我们之所以转换到C#并不是因为我们想要它成为面向对象编程,而是因为它更容易管理,而且它的面向对象编程风格没有同样的限制。 - RubberDuck
我已经为我所提出的每个要点添加了一些全VBA示例。代码再也没有比这更面向对象了。 - Mathieu Guindon

3
短答案是不和不。
VBA是面向对象的,允许您定义类并创建对象实例,但它缺乏通常与完整的面向对象编程语言相关联的功能,例如:
  • 封装和抽象:VBA在一定程度上提供了此功能。类可以保持私有,定义公共接口,但是类中没有构造函数的规定。类具有Class_Inititalize事件,可以进行一些构建,但不能带参数。传递参数需要一个公共工厂函数,以创建构造函数样式的设计模式。
  • 继承:在VBA中并不存在,但可以近似复制
  • 多态性:可以通过接口(使用Implements)在一定程度上实现,虽然不存在重载函数的能力(例如),每个“重载”技术上都需要一个唯一的函数名称。您可以通过将对象作为唯一参数传递到函数或子程序中,并根据属性值的变化来变化过程来解决此问题。

虽然在一定程度上可以使用对象,并且MS Office应用程序是基于对象模型的,但VBA并不是真正的面向对象语言。多态性无法达到您在C ++中熟悉的程度。


2
VBA可能不支持继承,但它支持组合,在许多方面是实现相同目的的不同方式。 - Blackhawk
5
大多数定义来看,我倾向于认为VBA实际上是一种面向对象的语言,但它省略了像Java或C#这样强大面向对象语言中人们习惯的许多常见特性。 - Blackhawk
1
@Blackhawk 我不知道,它甚至没有提供继承,我认为这是成为面向对象的基本要求。我可能会选择一个支持一些面向对象特性的基于对象的语言。 - stucharo
5
面向对象编程中继承的目的似乎是为了实现代码重用和多态性。组合和接口是实现相同目的的另一种方式,事实上有时也是更好的选择(参见“钻石问题”)。我同意,在面向对象编程中,代码重用和多态性是必要的,而VBA也具备这些功能。请参考“SOLID原则”,将其与VBA功能进行比较。 - Blackhawk
6
话虽如此,如果VBA是面向对象编程(OOP)的话,它绝对是面向对象语言中备受冷落的一个。 - Blackhawk
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接