Композиция VBA для Java-подобного наследования - PullRequest
0 голосов
/ 20 декабря 2018

Немного расширив этот вопрос Шаблон наследования VBA

Я воспроизводлю базовый шаблон наследования в VBA, но мне хотелось бы понять, существует ли более эффективный и краткий способдля этого.

Рассмотрим этот маленький тестовый пример.

IAnimal.cls

'declaration
Public Sub eat()
End Sub

Public Sub breathe()
End Sub

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

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

Test.bas

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

Выполнив это, я могу:

  • вызвать eat()метод для объектов Cat и Dog и имеют определенное переопределенное поведение
  • , вызывая методы только для подклассов (например, meow())
  • pass гетерогенная коллекция Animals для подпрограммы feed, которая может "безопасно" вызывать методы суперкласса Animal, а также запускать специальный код на основе подкласса Animal

Это кажетсяработать, но это громоздко: представьте, что вам нужно реализовать много подклассов Animal (Dog, Bird, Armadillo, PЛатип, Демогоргон, ...).Шаблон выше заставляет вас:

  1. повторно реализовывать все методы интерфейса IAnimal на ВСЕХ ПОДКЛАССАХ
  2. повторно реализовывать (снова) все методы, чтобы их можно было открыть изподкласс, даже если переопределение не требуется.Это необходимо, особенно если вы хотите получить доступ к ТАКЖЕ к методам только для подклассов.

Таким образом, вопрос заключается в следующем: существует ли более эффективный / краткий способ реализации этого примера (и ограничение перезаписи кода для каждого подкласса))

1 Ответ

0 голосов
/ 20 декабря 2018

tom не следует объявлять As Cat в первую очередь;процедура feed является излишней:

Sub Main()    
    Dim tom As IAnimal
    Set tom = New Cat    
    tom.eat    
End Sub

Теперь в классе Cat эти члены не должны существовать:

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

В SOLID / OOP выкод против интерфейса, а не конкретный тип - вот почему tom является IAnimal, а не Cat.При доступе через интерфейс IAnimal, Cat.eat полностью избыточен и предполагает, что Cat делает то, чего не делает IAnimal, что нарушает принципы SOLID: внезапно становится уместным, что IAnimal являетсяCat, и это не должно быть, потому что полиморфизм позволяет IAnimal быть чем-либо, а Принцип замещения Лискова (LSP - "L" в "SOLID") говорит любой код, который работает сIAnimal должен иметь возможность работать идентично независимо от того, какая реализация этого интерфейса ему предоставлена.

Соблюдение этих принципов означает, что ни одна реализация IAnimal не должна иметь копию IAnimal членов на своем интерфейсе по умолчанию(например, Cat.eat, против IAnimal.eat), и это полностью снимает ваш балл # 2:

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

Что касается пункта 1 ...

  1. заново реализовать все методы интерфейса IAnimal

Это требование компилятора, а не причуда VBA: будь то в Java, C #,или VBA, вы не можете сказать «я реализую интерфейс» ... без реализации его участников.Конечно, Java & C # допускают наследование классов, поэтому ваш базовый класс может сказать: «Я реализую интерфейс», реализовать все члены, и производные классы с удовольствием унаследуют их - но тогда это наследование , а не состав больше.

...