Немного расширяя этот вопрос Шаблон наследования 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 и иметь особое поведение Overriddenmeow())feed, которая может «безопасно» вызывать методы суперкласса Animal, а также запускать определенный код на основе подкласса AnimalКажется, это работает, но это громоздко: представьте, что вам нужно реализовать множество подклассов Animal (Dog, Bird, Armadillo, Platypus, Demogorgon, ...). Вышеупомянутый шаблон ВЫНУЖДАЕТ ВАС:
Итак, вопрос: есть ли более эффективный / краткий способ реализовать этот пример (и ограничить переписывание кода для каждого подкласса)?
Короче говоря, вы должны реализовать каждый член интерфейса. Вы можете узнать больше об этом здесь.
спасибо @MathieuGuindon за указание на принцип замены Лискова. Пытался исправить код соответствующим образом





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 делает то, чего не делает IAnimal, что нарушает принципы SOLID: внезапно становится актуальным, что Cat является IAnimal, а этого не должно быть, потому что полиморфизм позволяет IAnimal быть чем угодно, а Принцип замены Лискова (LSP - «L» от «SOLID») говорит, что любой код, работающий с IAnimal, должен иметь возможность работать идентично независимо от того, какая реализация этого интерфейса ему предоставлена.
Соблюдение этих принципов означает, что ни одна реализация IAnimal не должна иметь копию членов Cat.eat в интерфейсе по умолчанию (например, IAnimal.eat или tom), и это полностью устраняет ваш пункт №2:
- re-implements (again) all the methods, to expose them from the subclass, even when override is not necessary.
Что касается пункта 1 ...
- re-implement all the methods of the IAnimal interface
Это требование компилятора, а не причуда VBA: будь то в Java, C# или VBA, вы не можете сказать «Я реализую интерфейс» ... без реализации его членов. Конечно, Java и C# допускают наследование классов, поэтому ваш базовый класс может сказать: «Я реализую интерфейс», реализовать все члены, и производные классы с радостью унаследуют их - но тогда это наследование, а не сочинение.
Вы не можете реализовать интерфейс, не реализовав его членов, нет никакого способа обойти это. Пункт 2 поднимает флаг: если подкласс не может обрабатываться вызывающим кодом точно так же, как любой другой подкласс, то вы нарушаете принцип подстановки Лискова - нет необходимости повторно реализовывать все методы снова. и выставляем их из подкласса.