在定义标准接口后,不管是用 MkTypLib 应用程序创建类型库还是编译包含抽象类(指不包含代码,只有属性和方法的类模块)的 Visual Basic 工程,就可以在该部件提供的类中实现该接口。
设想有一个包括很多个部件的 LateCretaceous (近白垩纪)系统,每个部件都提供代表这个时代的植物群、动物区系和生存规则的对象。例如,某个部件提供 Velociraptor 类,而另一个部件提供 Tyrannosaur 类。
可以创建一个命名为 IPredator 的标准接口,其中包含 Hunt 和 Attack 方法:
'
抽象IPredator
类模块代码。Public Sub Hunt()
End Sub
Public Sub Attack(ByVal Victim As IDinosaur)
End Sub
请注意 Attack 方法的参数使用了另一个接口:IDinosaur。可能想用该接口包含的方法来描述恐龙(dinosaur)的普遍行为,如产蛋之类。这些行为也可能被很多类─ Velociraptor、Tyrannosaur、Brontosaur、Triceratops 等等实现。
还应注意到这些方法中不包含代码。IPredator 是一个仅定义了接口的抽象类(称之为抽象接口)。接口的具体实现根据实现该接口的对象而变化。
例如,Tyrannosaur 类可能用如下代码实现 IPredator:
Implements IPredator Private Sub IPredator_Hunt() '
本段代码完成如下功能:在岸边捕猎,直到遇到一只大恐龙。End Sub
Private Sub IPredator_Attack(ByVal Victim As IDinosaur)
'
本段代码完成如下功能:猛攻、咬。End Sub
重点 在“通过接口的实现提供多态性”中讲到,接口即协议。必须实现接口中所有的属性和方法。
而 Velociraptor 类可能按如下所示代码实现 IPredator:
Implements IPredator Private Sub IPredator_Hunt() '
扇形围猎,寻找小恐龙,合围大恐龙。End Sub
Private Sub IPredator_Attack(ByVal Victim As IDinosaur)
'
本段代码完成如下功能:从各个方向突进,猛砍猎物并治服它。End Sub
一旦拥有实现 IPredator 的类,就可以将原有的应用程序逐个升级,使用新的更具竞争力的接口。可以通过把 Velociraptor 或 Tyrannosaur 对象赋给 IPredator 类型的变量的方法来访问 Hunt 和 Attack 方法,如下所示:
Dim tyr As New Tyrannosaur
Dim prd As IPredator
Set prd = tyr
prd.Hunt
也可以声明过程参数为 As IPredator
,然后把任何实现了 IPredator 接口的对象传递给该过程,如下所示:
Public Sub DevourTheCompetition(ByVal Agent As _
IPredator, ByVal Target As IDinosaur)
Agent.Hunt
Agent.Attack Target
End Sub
上面显示的 Sub 过程可以把任何一种肉食恐龙作为第一个参数,把任何一种恐龙作为第二个参数调用。过程的调用者可以使用任何符合这种情况的肉食恐龙。这种灵活性有助于保持商业优势。
包含抽象接口的类型库为实现和使用该接口提供了引用点。
要实现一个接口,必须使用“引用”对话框设置对该类型库的引用。这是因为类型库中包含接口成员的指定参数和返回类型的所需信息。
同样,对于任何使用已经实现抽象接口的对象的应用程序,也必须设置对描述该接口的类型库的引用。因为无法解决名称冲突的问题,所以部件的类型库不能包含所实现的接口的信息。
重点 为了在进程间或远程计算机之间调度数据,进程外部件必须在其安装程序中包括描述抽象接口的类型库。进程内部件也应该包括这些类型库,因为开发者可能要将该类型库的对象传给本地、或远程计算机上的其它应用程序。请参阅“调试、测试和部署部件”的“部署部件”。
下面是关于实现多接口的指南:
下一节论述如何使用上述的指南来逐渐增强一个系统。
毫无疑问,留心的读者肯定会发现在前面给出的代码中有一个缺陷。如果肉食恐龙只吃其它的恐龙,那它们怎么能使这种哺乳动物繁衍下去呢?一个更通用的 IPredator 接口应该可以接收任何 IAnimal 对象作为食物。
这说明了使用多接口技术进行部件软件开发的重要优点:当 LateCretaceous 系统演化为 Pliestocene 系统时,提供肉食恐龙对象的部件就可以用提供 SaberTooth 和 DireWolf 对象的部件代替。
以前开发的使用恐龙对象的应用程序使用新的肉食类也许仍能工作得相当出色,只要其中未包括专用于恐龙的代码。
以这种方式使用多接口要记住的重点:
Implements 语句也允许重用已有对象中的代码。这种形式的代码重用中,新的对象(称之为外部对象)在其初始化事件中创建已有对象(或叫内部对象)的一个实例。
外部对象除了实现了抽象接口外,也实现了内部对象的缺省接口。(要做到这一点,使用“引用”对话框添加对提供内部对象的部件的引用。)
向外部对象添加代码实现内部对象的属性和方法时,只要内部对象所提供的功能符合外部对象的需要,就可以沿用。
例如,Tyrannosaur 类实现了 Dinosaur 对象的接口(而不是一个抽象的 IDinosaur 接口)。该 Dinosaur 对象有一个 LayEggs 方法,则只需简单的沿用就可以实现 Tyrannosaur 类:
Private dnoInner As Dinosaur Private Sub Class_Initialize() Set dnoInner = New Dinosaur End Sub Private Sub Dinosaur_LayEggs() '
沿用到内部对象。dnoInner.LayEggs
End Sub
这是一种十分有效和灵活的重用代码方式,因为外部对象可以选择在指派给内部对象之前或之后执行自己的代码,或者只是沿用到内部对象。
详细信息 使用 Implements 语句的代码重用在《Visual Basic 程序员指南》“用对象编程”的“多态性”中有更详细的论述。