Интерфейс, реализующий несколько интерфейсов в VBA - PullRequest
0 голосов
/ 15 апреля 2020

Я хотел бы создать интерфейс, который реализует несколько интерфейсов, а затем создать класс, который реализует этот интерфейс. Например:

IFlyable модуль:

Public Sub Fly()
End Sub

Public Function GetAltitude() As Long
End Function

ISИзменяемый модуль:

Public Sub Swim()
End Sub

Public Function GetDepth() As Long
End Function

Модуль 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

Все это прекрасно компилируется , Но если я объявляю объект типа IFlySwim, предиктивный текст в VBA дает мне:

IFlyable_Fly, IFlyable_GetAltitude, ISwimmable_Swim

И попытка создать класс, реализующий IFlySwimmable, просто не не работает.

Class Duck:

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

При нажатии на кнопку компиляции выдается сообщение об ошибке: «Ошибка компиляции: объектному модулю необходимо реализовать IFlyable_Fly для интерфейса« IFlySwim ».

Так что это заставляет меня поверить, что Implement использование интерфейса в другом интерфейсе не работает. Или, по крайней мере, это не имеет смысла с точки зрения VBA. Это понятно, потому что я на самом деле не предоставляет реализацию для IFlyable и ISwimmable в IFlySwim. Что я действительно хочу сделать, так это отложить реализацию для IFlyable и ISwimmable до класса, который реализует оба из них.

Так что теперь, если мой Duck класс:

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

Тогда, когда я go его использую, прогнозирующий выпадающий список дает мне:

Duck usage

Я мог бы разыграть Duck или IFlyable или ISwimmable нам e как таковой:

Duck usage 2

Но что, если я хотел создать функцию или вспомогательный модуль, который принимает Flyable / Swimmable? Нужно ли мне создавать совершенно отдельный интерфейс IFlySwim, который содержит все подфункции / функции из IFlyable и ISwimmable, а затем изменить мой класс Duck так, чтобы он реализовывался только из IFlySwim?

Ответы [ 2 ]

0 голосов
/ 16 апреля 2020

Методы / свойства интерфейса (т. Е. Методы / свойства с префиксом подчеркивания) не должны отображаться как public c. Они должны быть реализованы для выполнения контракта интерфейса в производном классе, но они должны быть помечены как частные. Как только вы это сделаете, вы можете выставить publi c членов с именами методов, такими как Fly или GetAltitude (см. Ниже):

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

И ваш тестовый код станет следующим: (см. Ниже) )

Sub InterfaceTest()

    Dim ducky As New Duck

    ducky.Fly
    Debug.Print ducky.GetAltitude()

    ducky.Swim
    Debug.Print ducky.GetDepth()

End Sub

Но что, если бы я хотел создать функцию или подпрограмму, которая принимает Flyable / Swimmable? Нужно ли создавать полностью отдельный интерфейс IFlySwim, который содержит все Sub / функции из IFlyable и ISwimmable, а затем изменить свой класс Duck, чтобы он реализовывался только из IFlySwim?

Краткий ответ: Да ,

Почему?

Потому что VBA / VB6 не поддерживает наследование полностью. Чтобы сделать то, что вы просите, вы должны создать третий класс, который наследуется от ISwimmable и IFlyable, а затем реализовать этот класс в других классах.

На полностью OOP языке, таком как C#, вы можете выполнить следующее: (см. Ниже)

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 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();

    }
}

Производит:

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


Mallard Duck:
Flying with wings!
100
Swimming!
10
Headed for land!
0 голосов
/ 15 апреля 2020

К сожалению, так работает наследование по композиции. Однако вы должны понимать, что ваш класс Duck связывает интерфейс с конкретной реализацией реализаций функций. Вам нужно использовать второй уровень косвенности

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

Из этого вы можете видеть, что 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

, которое может или не может быть полезно для вас.

...