类java继承的VBA组合

Fed*_*nis 3 oop inheritance vba catia

在这个问题上展开一点VBA 继承模式

我在 VBA 中重现了一个基本的继承模式,但我想了解是否有更有效和更简洁的方法来实现这一点。

考虑这个小测试用例。

IAnimal.cls

'declaration
Public Sub eat()
End Sub

Public Sub breathe()
End Sub
Run Code Online (Sandbox Code Playgroud)

Animal.cls :超类

Implements IAnimal

' method implementation
Private Sub IAnimal_eat()
    Debug.Print "I'm eating something..."
End Sub

Private Sub IAnimal_breathe()
    Debug.Print "I'm brething..."
End Sub
Run Code Online (Sandbox Code Playgroud)

Cat.cls :Animal 的一个子类

Private super As IAnimal

Implements IAnimal

Private Sub Class_Initialize()
    Set super = New Animal
End Sub


'#------------------------------------------------
' methods called when object is accessed as an IAnimal implementor. 
' I HAVE TO re-implement all of them also here in the subclass (in java I don't need to. It's sufficient to implement them in the superclass)
Private Sub IAnimal_eat()
    Me.eat
End Sub

Private Sub IAnimal_breathe()
    Me.breathe
End Sub


'#--------------------------------------------------
' subclass-only methods
' To access those methods I MUST DECLARE the object as Cat (Dim tom as Cat)
Public Sub meow()
Debug.Print "meow..."
End Sub


'#------------------------------------------------ 
' superclass methods
' Since I need to declare the cat object as a Cat (see above)
' I'm FORCED TO explicitly re-implement all of the superclass methods,
' even those that I don't need to override
' otherwise I can't access them

'@Override
Public Sub eat()
    Debug.print "I'm  eating a fish!"
End Sub

'I'm forced to re-implement also this method, in order to use it directly on a *Cat* object
'@Unnecessary-Override
Public Sub breathe()
    super.breathe 
End Sub
Run Code Online (Sandbox Code Playgroud)

测试数据库

Sub Main()

    Dim snowball As IAnimal
    Set snowball = New Cat

    Dim tom As Cat
    Set tom = New Cat

    snowball.meow  'ERROR Method or data member not found <---- cannot access the Cat-only method "meow"
    tom.meow  '<--- prints "meow"

    ' creates a Dog, another subclass of Animal
    Dim pluto As Dog
    Set pluto = New Dog

    'create a collection for all my animals
    Dim myPets As Collection
    Set myPets = New Collection

    myPets.Add tom
    myPets.Add pluto

    Call feed(myPets) '<---- prints
                            'I 'm eating a fish
                            'meow...
                            'I 'm eating a bone
                            'woof...

End Sub

' a routine for showing how to manage an heterogeneous collection of animals
Sub feed(animals As Collection)

    For Each a In animals

        a.eat

        If TypeOf a Is Cat Then
            a.meow
        End If

        If TypeOf a Is Dog Then
            a.woof
        End If

    Next

End Sub
Run Code Online (Sandbox Code Playgroud)

通过这样做,我可以:

  • 调用eat()Cat 和 Dog 对象上的方法并具有特定的 Overridden 行为
  • 调用仅子类的方法(如meow()
  • 异类feed的 Animal集合传递给子程序,该子程序可以“安全地”调用 Animal 超类方法并触发基于 Animal 子类的特定代码

这似乎有效但很麻烦:假设您需要实现许多 Animal 子类(Dog、Bird、Armadillo、Platypus、Demogorgon 等)。上面的模式迫使你:

  1. 在所有子类上重新实现 IAnimal 接口的所有方法
  2. 重新实现(再次)所有方法,从子类公开它们,即使不需要覆盖。如果您还想访问仅限子类的方法,则特别需要这样做。

所以问题是:有没有更有效/简洁的方法来实现这个例子(并限制每个子类的代码重写)?

Mat*_*don 5

tom不应该首先声明As Cat;该feed程序是多余的:

Sub Main()    
    Dim tom As IAnimal
    Set tom = New Cat    
    tom.eat    
End Sub
Run Code Online (Sandbox Code Playgroud)

现在,在Cat类中,这些成员不需要存在:

'Superclass methods --- I have to explicitly override all methods :(
Public Sub eat()
    super.eat 
    Debug.print "...a fish!"
End Sub
Run Code Online (Sandbox Code Playgroud)

在 SOLID/OOP 中,您针对接口而不是具体类型进行编码 - 这就是为什么tom是 anIAnimal而不是Cat. 通过它的IAnimal接口访问,Cat.eat是完全多余的,并暗示 aCat做某事IAnimal不做,这违反了 SOLID 原则:突然间 anIAnimal是 a变得相关,Cat它不应该是,因为多态允许IAnimal是任何东西,和Liskov 替换原则(LSP - “SOLID”的“L”)说任何与 anIAnimal一起工作的代码都应该能够以相同的方式工作,而不管它给出了该接口的什么实现。

遵守这些原则意味着任何IAnimal实现都不应该IAnimal在其默认接口(例如Cat.eat, vs IAnimal.eat)上有成员的副本,这完全消除了您的观点#2:

  1. 重新实现(再次)所有方法,以从子类公开它们,即使不需要覆盖。

至于第1点...

  1. 重新实现 IAnimal 接口的所有方法

这是编译器的要求,而不是 VBA 的怪癖:无论是在 Java、C# 还是 VBA 中,您都不能说“我正在实现一个接口”……而不实现其成员。当然 Java 和 C# 允许类继承,所以你的基类可以说“我正在实现一个接口”,实现所有成员,派生类会很高兴地继承它们 - 但是,那是继承,不再是组合