简体   繁体   English

在 VBA 中实现多个接口的接口

[英]Interface implementing multiple interfaces in VBA

I would like to create an Interface that implements multiple interfaces, and then make a class that implements that interface.我想创建一个实现多个接口的接口,然后制作一个实现该接口的 class。 For example:例如:

IFlyable module: IFlyable 模块:

Public Sub Fly()
End Sub

Public Function GetAltitude() As Long
End Function

ISwimmable module: ISwimmable 模块:

Public Sub Swim()
End Sub

Public Function GetDepth() As Long
End Function

IFlySwim module: IFlySwim 模块:

Implements IFlyable
Implements ISwimmable

Public Sub IFlyable_Fly()
End Sub

Public Function IFlyable_GetAltitude() As Long
End Function    

Public Sub ISwimmable_Swim()
End Sub

Public Function ISwimmable_GetDepth() As Long
End Function

This all compiles just fine.这一切都编译得很好。 But if I declare an Object of type IFlySwim, the predictive text in VBA gives me:但是,如果我声明一个 IFlySwim 类型的 Object,VBA 中的预测文本会给我:

IFlyable_Fly、IFlyable_GetAltitude、ISwimmable_Swim

And trying to create a Class that implements IFlySwimmable just doesn't work.并且试图创建一个实现 IFlySwimmable 的 Class 是行不通的。

Class Duck: Class 鸭:

Implements IFlySwim

Public Sub IFlySwim_IFlyable_Fly()
    Debug.Print "Flying with wings!"
End Sub

Public Function IFlySwim_IFlyable_GetAltitude() As Long
    IFlySwim_IFlyable_GetAltitude = 30
End Function

Public Sub IFlySwim_ISwimmable_Swim()
    Debug.Print "Swimming with feet!"
End Sub

Public Function IFlySwim_ISwimmable_GetDepth() As Long
    IFlySwim_ISwimmable_GetDepth = 20
End Function

Pressing the compile button gives me the error: "Compile error: Object module needs to implement 'IFlyable_Fly' for interface 'IFlySwim'.按编译按钮给我错误:“编译错误:Object 模块需要为接口 'IFlySwim' 实现 'IFlyable_Fly'。

So this leads me to believe that Implement ing an interface within another interface Doesn't Work.所以这让我相信在另一个接口中Implement一个接口是行不通的。 Or at least, it doesn't make sense from VBA's point of view.或者至少,从 VBA 的角度来看,它没有意义。 Which is understandable, because I'm not actually providing an implementation for IFlyable and ISwimmable in IFlySwim .这是可以理解的,因为我实际上并没有在IFlySwim中提供IFlyableISwimmable的实现。 What I really want to do is defer implementation for IFlyable and ISwimmable to a class that implements both of them.我真正想做的是将IFlyableISwimmable的实现推迟到实现它们的 class 。

So now, if my Duck class is:所以现在,如果我的Duck class 是:

Implements IFlyable
Implements ISwimmable

Public Sub IFlyable_Fly()
    Debug.Print "Flying with wings!"
End Sub

Public Function IFlyable_GetAltitude() As Long
    IFlyable_GetAltitude = 30
End Function

Public Sub ISwimmable_Swim()
    Debug.Print "Swimming with feet!"
End Sub

Public Function ISwimmable_GetDepth() As Long
    ISwimmable_GetDepth = 20
End Function

Then when I go to use it, the predictive dropdown gives me:然后当我 go 使用它时,预测下拉菜单给了我:

鸭子的用法

I could cast Duck to either the IFlyable or ISwimmable to use as such:我可以将Duck转换为IFlyableISwimmable来使用:

鸭子用法2

But what if I wanted to create a Function or Sub that accepts a Flyable/Swimmable?但是,如果我想创建一个接受 Flyable/Swimmable 的 Function 或 Sub 怎么办? Do I have to create a completely separate interface called IFlySwim that contains all of the Sub/Functions from IFlyable and ISwimmable , and then modify my Duck class to only implement from the IFlySwim ?我是否必须创建一个名为 IFlySwim 的完全独立的接口,其中包含来自IFlyableISwimmable的所有子/功能,然后修改我的Duck class 以仅从IFlySwim实现?

Unfortunately, that is how inheritance by composition works.不幸的是,这就是 inheritance 的工作原理。 However you should realise that your Duck class is tying the interface to the concrete implementation of the function implementations.但是,您应该意识到您的 Duck class 将接口与 function 实现的具体实现联系起来。 You need to use a second level of indirection您需要使用第二级间接

Implements IFlyable
Implements ISwimmable

Private Sub IFlyable_Fly()
    Fly
End Sub

|Private Function IFlyable_GetAltitude() As Long
    IFlyable_GetAltitude=GetAltitude
End Function

Private Sub ISwimmable_Swim()
    Swim
End Sub

Private Function ISwimmable_GetDepth() As Long
    ISwimmable=GetDepth
End Function

Public Sub Fly()
    Debug.Print "Flying with wings!"
End Sub

Public Function GetAltitude() As Long
    GetAltitude = 30
End Function

Public Sub Swim()
    Debug.Print "Swimming with feet!"
End Sub

Public Function GetDepth() As Long
    GetDepth = 20
End Function

From this you can see that GetAltitude and GetDepth could both refer to a property of VerticalPosition从这里你可以看到 GetAltitude 和 GetDepth 都可以引用 VerticalPosition 的属性

Private Function IFlyable_GetAltitude() As Long
        IFlyable_GetAltitude=GetVerticalPosition
End Function


Private Function ISwimmable_GetDepth() As Long
    ISwimmable_GetDepth=- GetVerticalPosition
End function

Which may or may not be helpful top you.这可能对您有帮助,也可能对您没有帮助。

Interface methods/properties (ie methods/properties prefixed with an underscore) should not be exposed as public.接口方法/属性(即以下划线为前缀的方法/属性)不应公开。 They must be implemented to fulfill the contract of the interface in the derived class, but they should be marked as private.必须实现它们以履行派生 class 中的接口契约,但应将它们标记为私有。 Once you have done so, you can expose public members with method names like Fly or GetAltitude (see below):完成此操作后,您可以使用FlyGetAltitude等方法名称公开公共成员(见下文):

Option Explicit

Implements ISwimmable
Implements IFlyable

'********************************************************
'Public Methods
'********************************************************
Public Function GetDepth() As Long

    GetDepth = 10

End Function

Public Sub Swim()

    Debug.Print "Swimming!"

End Sub

Public Function GetAltitude() As Long

    GetAltitude = 50

End Function


Public Sub Fly()

    Debug.Print "Flying with wings!"

End Sub


'********************************************************
'Private Methods
'********************************************************
Private Function ISwimmable_GetDepth() As Long
End Function

Private Sub ISwimmable_Swim()
End Sub


Private Function IFlyable_GetAltitude() As Long
End Function

Private Sub IFlyable_Fly()
End Sub

And your test code becomes the following: (see below)您的测试代码如下:(见下文)

Sub InterfaceTest()

    Dim ducky As New Duck

    ducky.Fly
    Debug.Print ducky.GetAltitude()

    ducky.Swim
    Debug.Print ducky.GetDepth()

End Sub

But what if I wanted to create a Function or Sub that accepts a Flyable/Swimmable?但是,如果我想创建一个接受 Flyable/Swimmable 的 Function 或 Sub 怎么办? Do I have to create a completely separate interface called IFlySwim that contains all of the Sub/Functions from IFlyable and ISwimmable, and then modify my Duck class to only implement from the IFlySwim?我是否必须创建一个名为 IFlySwim 的完全独立的接口,其中包含来自 IFlyable 和 ISwimmable 的所有子/功能,然后修改我的 Duck class 以仅从 IFlySwim 实现?

Short answer: Yes.简短的回答:是的。

Why?为什么?

Because, VBA/VB6 does not support inheritance fully.因为,VBA/VB6 不完全支持 inheritance。 To do what you ask, you would have create a third class that inherits from ISwimmable and IFlyable , and then implement that class in other classes.按照您的要求,您将创建第三个 class 继承自ISwimmableIFlyable ,然后在其他类中实现该 class 。

In a fully OOP language like C# , you could to the following: (see below)在像C#这样的完全 OOP 语言中,您可以执行以下操作:(见下文)

public interface IFlyable   {

    void Fly(); 
    int GetAltitude(); 

} 


public interface ISwimmable {

    void Swim();
    int GetDepth();

} 

//Base Class
public abstract class BaseDuck: ISwimmable, IFlyable    {

    public BaseDuck(){}

    public void Fly()   {

        Console.WriteLine("Flying with wings!"); 

    } 

    public virtual int GetAltitude()    {

        return 50; 

    } 

    public void Swim()  {

        Console.WriteLine("Swimming!"); 

    } 

    public virtual int GetDepth()   {

        return 10; 

    } 


}

//Derived Class
public class SeaDuck: BaseDuck  {

    public SeaDuck(){}

    public override int GetAltitude()   {

        return 50; 

    } 

    public override int GetDepth()  {

        return 100; 

    } 

    public void RideWaves() {

        Console.WriteLine("Riding waves!");

    }

}

//Derived Class
public class MallardDuck: BaseDuck  {

    public MallardDuck(){}

    public override int GetAltitude()   {

        return 100; 

    } 

    public override int GetDepth()  {

        return 10; 

    } 

    public void HeadToLandForWinter()   {

        Console.WriteLine("Headed for land!");

    }

}

Using the following to test: (see below)使用以下测试:(见下文)

using System;

public class Program
{
    public static void Main()
    {
        SeaDuck seaDuck = new SeaDuck();

        Console.WriteLine("Sea Duck:");
        seaDuck.Fly();
        Console.WriteLine(seaDuck.GetAltitude().ToString()); 

        seaDuck.Swim();
        Console.WriteLine(seaDuck.GetDepth().ToString()); 

        seaDuck.RideWaves(); 

        Console.WriteLine("\n");

        Console.WriteLine("Mallard Duck:");
        MallardDuck mallardDuck = new MallardDuck();
        mallardDuck.Fly();
        Console.WriteLine(mallardDuck.GetAltitude().ToString()); 

        mallardDuck.Swim();
        Console.WriteLine(mallardDuck.GetDepth().ToString()); 

        mallardDuck.HeadToLandForWinter();

    }
}

Produces:生产:

Sea Duck:
Flying with wings!
50
Swimming!
100
Riding waves!


Mallard Duck:
Flying with wings!
100
Swimming!
10
Headed for land!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM