对我来说,这既是关于学习面向对象方法论的问题,又是关于VBA语法的问题。假设我创建了几个类,例如Car,Truck,Bus等。并且我创建了另一个类SpeedCalculator,我的车辆实例将实例化并包含在其中。 (作为一个新手,请注意,这是将类声明为静态而不是实例化的好时机,我不认为这是vba不能做的...。)现在,此速度计算器将是没有简单的速度计。而是为了示例,它会根据温度,风速,RPM等来计算速度。
现在的问题是,所包含的对象如何收集其输入,这些输入仅在容器对象中可用(车辆对象可能实现接口(如果VBA甚至可以实现此接口...))。 “父母。”是错误的,我最终发现,b / c parent-child是一个继承关系(VBA再次没有该继承关系),而不是一个包含关系,所包含对象的父对象是一个Excel Application(不是我的对象) 。因此,如果还有另一个关键字可以引用容器属性,那似乎很好。我希望我不仅错过了一些简单的事情。还是这种引用会破坏面向对象的封装原理呢?
我猜第二种方法是通过“ Me”作为参数将容器传递给包含的容器。但是然后您必须乘以所包含的所有方法,以重载它们(如果VBA甚至可以做到这一点...),或者使用不同名称的版本-由于容器的类型不同(我们可以更理想化,避免声明为变体或“对象”?)。
我猜是#3门是最后一扇门吗?这将是传递(烦人)一连串的争论。所有这些的定义将趋于破坏使我的小计算器班级整齐的目的?
最佳答案
从您的问题对我来说还不清楚,您是否已经知道VBA和/或OO,并且只是问如何使用VBA的面向对象功能。如果您对VBA和OO都不熟悉,请参阅以下有关VBA为什么不是学习OOD / OOP的很好工具的一些想法。
为了解决您的问题的一般部分,VBA类可以实现接口。这是您在VBA中表示接口继承(“ is-a”关系)的方式。没有直接的方法可以表达VBA中实现的继承。相反,要使一个类继承另一个类的实现,您需要第一个实现第二个的接口,包含第二个的实例,然后将调用委托给该实例。有关更多信息,请参见以下答案:
VBA inheritance, analog of super
这里有一个链接,我将在这里重复到《 Visual Studio 6.0程序员指南》:
http://msdn.microsoft.com/en-us/library/aa240846(v=VS.60).aspx
这是对OOP的“ VBA方式”的简短介绍(尽管它是针对VB6而非VBA编写的)。
现在,对于您有关设计的特定问题:“所包含的对象如何收集其输入(仅在容器对象中可用)”。
您需要考虑这里实际建模的内容。无论您如何实现它,“速度计算器”都应该只了解非常特定的一组输入,而不是使用它的任何车辆的整个内部状态。如您所述,在VBA中,没有静态类。而是使用常规代码模块,并具有一个从车辆类内部调用的函数:
Public Function calcSpeed(temp, windspeed, rpm)
'do calc based only on parms passed in...
End Function
如果需要大量的参数,因为那是计算的工作原理,那就这样吧。不要试图隐藏它。当然,如果有太多的话,可以将它们包装在
Type
或类中。现在,每种不同的车辆是否都从完全相同的状态参数集中以完全相同的方式计算速度?如果是这样,则具有由您的“基础车辆”类实现的
speed
属性或方法,然后从那里调用calcSpeed
。但是也许是这样的情况,不同种类的车辆具有不同的状态参数,或使用不同的计算方法,或者计算是相同的,但并非每种车辆类型都提供每种参数。在那种情况下,将
speed
方法放在基本的车辆界面中,但是在实现每个子类时需要“覆盖”它。 (也许calcSpeed
太简单了,您最终会得到一个速度计算帮助器函数库。)我不会做的一件事就是拥有一个通用的SpeedCalculator类,该类接受一个Vehicle参数,然后对其状态进行查询以进行计算。这些经典文章很好地表达了为什么不这样做的原因:
http://media.pragprog.com/articles/may_04_oo1.pdf
http://pragprog.com/articles/tell-dont-ask
http://www.cmcrossroads.com/bradapp/docs/demeter-intro.html
还有这个:
http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf
有一个我喜欢的报价:
所以,这段代码有什么不好的地方
(除了人为地作恶
例)?好吧,让我们翻译一下
该代码实际上正在
真实语言:
显然,当
Paperboy停下来要求付款,
顾客将要转向
周围,让报童把
从后兜里掏出钱包,然后
拿出两美元。
我不知道
你,但我很少让别人来处理
我的钱包。有一些
“现实世界”的问题,而不是
提到我们相信报童
说实话,只是拿出什么
他欠了。如果我们未来的电子钱包对象
持有信用卡,报童有
也可以访问这些...但是基本
问题是“报童正在
比他有更多的信息
需要是”。
那很重要
概念...现在是“ Paperboy”课程
“知道”客户有一个
钱包,并且可以操纵它。什么时候我们
编译Paperboy类,它将
需要客户类和钱包
类。现在这三个班
'紧密耦合'。如果我们改变
钱包类,我们可能必须
对其他两个类的更改。
根据评论中的建议添加:
这并不是说您不能轻易在
Speedometer
中包含类Vehicle
的实例。 (我的简单函数示例可能太简单了。也许您需要一个类来对速度计的其他内容进行建模-它们具有质量,占用空间等。)这就是两个类相互依赖的方式。在此示例中,Vehicle
需要了解Speedometer
。但是,为什么相反是正确的呢?如果Speedometer
将Vehicle
作为参数,然后要求它提供计算速度所需的特定知识,则代码肯定可以工作。但是,您已经将Speedometer
与Vehicle
的耦合更加紧密。首先使用OO方法的原因之一是因为它使您可以更精确地了解概念之间的关系。最好让
Vehicle
告诉Speedometer
,“这是关于世界的一些事实。请给我一个速度。”而不是“在这里,我是,Me
,这是让您迷恋的Vehicle
。我,只要您需要处理与我有关的任何事情,然后给我回头的速度。” (请注意,“关于世界的事实”是原始温度,风速等,还是某些SpeedometerInput
类型/类的实例都不是问题。这是因为里程表不需要完全了解车辆。 )在一个简单的示例中,使用最精确的界面可以避免很多麻烦。但是,如果将许多设计决策加在一起,它就会变得巨大。
最后,如果您有选择,我不会将VBA用作学习面向对象设计或编程的工具。您可以在VBA中执行“ OOP”,但是可以使用Microsoft / COM特定的方式,这实际上是1990年代中期的遗物。您可以在stackoverflow上浏览,以获取许多示例示例,这些示例通常是用OO编程语言(及其更好的库)完成的,这些示例在VBA中既麻烦又棘手。我曾问过或回答过以下几个问题:
Is there a way to overload the constructor / initialize procedure for a class in VBA?
Is there a way to write an equality test for a VBA class with private members without exposing knowledge of the existence of those private members?
Restrict type in a Collection inside a class module
Excel-VBA - Is there anything like Javas Set container in VBA?
因此,除非您因为无法在计算机上安装MS Office之外而不能安装其他任何东西而无法学习VBA,或者除非您打算使用Excel,Access等并且打算使用VBA进行很多VBA工作,否则除非您受此限制OOP可以提供帮助的一些问题,我会去其他地方看看。在Windows上免费提供Python,.NET或Java,并且有大量资源可供初学者使用。
关于class - VBA引用容器对象-语法和面向对象的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5730457/