Composition and polymorphism

tiredofit

Well-known Member
Joined
Apr 11, 2013
Messages
1,926
Office Version
  1. 365
  2. 2019
Platform
  1. Windows
VBA lacks Inheritence but Composition is usually preferred.

To my limited knowledge, Class interfaces are used "to promote" polymorphism in VBA.

This article shows composition:

Code:
https://www.microsoftpressstore.com/articles/article.aspx?p=2225071&seqNum=2

Here is some of the code:

Code:
' ClsPolicy

Dim p_MonthlyPremium As Currency

Public Property Get MonthlyPremium() As Currency
    MonthlyPremium = p_MonthlyPremium
End Property

Public Property Let MonthlyPremium(ByVal MonthlyPremium As Currency)
    p_MonthlyPremium = MonthlyPremium
End Property

Public Function CalculateAnnualPolicyValue() As Currency
    CalculateAnnualPolicyValue = p_MonthlyPremium * 12
End Function

and this is a derived class:

Code:
' ClsHomePolicy

Dim p_Policy As clsPolicy

Private Sub Class_Initialize()
    Set p_Policy = New clsPolicy
End Sub
Private Sub Class_Terminate()
    Set p_Policy = Nothing
End Sub

Public Property Get MonthlyPremium() As Currency
    MonthlyPremium = p_Policy.MonthlyPremium
End Property

Public Property Let MonthlyPremium(ByVal MonthlyPremium As Currency)
    p_Policy.MonthlyPremium = MonthlyPremium
End Property

Public Function CalculateAnnualPolicyValue() As Currency
    CalculateAnnualPolicyValue = p_Policy.CalculateAnnualPolicyValue() + 50
End Function

What I don't understand is couldn't the above be replicated using class interfaces, ie:

Code:
Implements ClsInterface

Dim p_MonthlyPremium As Currency

Public Property Get ClsInterface_MonthlyPremium() As Currency
    ClsInterface_MonthlyPremium = p_MonthlyPremium
End Property

Public Property Let ClsInterface_MonthlyPremium(ByVal MonthlyPremium As Currency)
    p_MonthlyPremium = MonthlyPremium
End Property

Public Function ClsInterface_CalculateAnnualPolicyValue() As Currency
    ClsInterface_CalculateAnnualPolicyValue = p_MonthlyPremium * 12
End Function

and

Code:
Implements ClsInterface

Dim p_MonthlyPremium As Currency

Public Property Get ClsInterface_MonthlyPremium() As Currency
    ClsInterface_MonthlyPremium = p_MonthlyPremium
End Property

Public Property Let ClsInterface_MonthlyPremium(ByVal MonthlyPremium As Currency)
    p_MonthlyPremium = MonthlyPremium
End Property

Public Function ClsInterface_CalculateAnnualPolicyValue() As Currency
    ClsInterface_CalculateAnnualPolicyValue = p_MonthlyPremium * 12 + 50
End Function

with the interface:

Code:
Public Property Get MonthlyPremium() As Currency

End Property

Public Property Let MonthlyPremium(ByVal MonthlyPremium As Currency)

End Property

Public Function CalculateAnnualPolicyValue() As Currency

End Function

If so, which method would be preferable, composition or interfaces?

Thanks
 

Excel Facts

Remove leading & trailing spaces
Save as CSV to remove all leading and trailing spaces. It is faster than using TRIM().
I think it is a question of determining which design is best suited for the task.

A base class (such as ClsPolicy) executes actual code that will be, common to, and shared by derived classes, whereas an interface class (such as ClsInterface) doesn't execute code.

In the case of opting for the interface approach, the actual execution of the code would be taken care of by the implementing class. Each implementation can vary and the code need not be the same.

So:
- Wanting to use a Base Class (inheritance) would imply wanting to use common\shared code by all inheriting client classes.
- Wanting to use an Interface (polymorphism) would imply wanting to execute different code logics by different implementing client classes .
 
Upvote 0
Solution
I think it is a question of determining which design is best suited for the task.

A base class (such as ClsPolicy) executes actual code that will be, common to, and shared by derived classes, whereas an interface class (such as ClsInterface) doesn't execute code.

In the case of opting for the interface approach, the actual execution of the code would be taken care of by the implementing class. Each implementation can vary and the code need not be the same.

So:
- Wanting to use a Base Class (inheritance) would imply wanting to use common\shared code by all inheriting client classes.
- Wanting to use an Interface (polymorphism) would imply wanting to execute different code logics by different implementing client classes .
Many thanks for your explanation.

As I'm learning about Class Interfaces, I was planning to convert all my If-Then-Else / Select Cases to Interfaces but I don't think that's a wise approach.
 
Upvote 0
As I'm learning about Class Interfaces, I was planning to convert all my If-Then-Else / Select Cases to Interfaces but I don't think that's a wise approach.

I would personally prefer to go the Interface (polymorphism) route should there be lots of *If-Then-Else / Select Cases* in my project. I think the overall design becomes more intuitve but that is just a guess.

Two things I like about implementing interfaces is the abillity to type cast and the ability to force vba intellisense to show only relevant Properties & Methods.

Consider the following example:

1- IAnimal Interface.
VBA Code:
Option Explicit

Public Sub MakeSound()
    '
End Sub

2- IBird Interface.
VBA Code:
Option Explicit

Public Sub Fly()
    '
End Sub



3- CCat Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal

Private Sub IAnimal_MakeSound()
    'Cat implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Meow!!!  Meow!!!", , "Cat"
End Sub

4- CDog Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal

Private Sub IAnimal_MakeSound()
    'Dog implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Woof!!!  Woof!!!", , "Dog"
End Sub

5- CDuck Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal
Implements IBird

Private Sub IAnimal_MakeSound()
    'Dog implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Quack!!!  Quack!!!", , "Duck"
End Sub

Private Sub IBird_Fly()
    'Duck implementation of the IBird Interface [Fly Method]:
    MsgBox "Knock Knock Knock Knock !!", , "Duck"
End Sub




Usage in Standard Module

VBA Code:
Option Explicit

Sub Interfaces_Example()

    Dim Cat As IAnimal
    Dim Dog As IAnimal
 
    Set Cat = New CCat
    Set Dog = New CDog
 
    Cat.MakeSound
    Dog.MakeSound

    Dim Duck As IAnimal
    'QueryInterface asking for the IAnimal Interface.
    Set Duck = New CDuck 
    Duck.MakeSound
 
    Dim FlyingDuck As IBird
    'Casting:
    'QueryInterface asking for the IBird Interface.
    Set FlyingDuck = Duck
    FlyingDuck.Fly
 
    'Different addresses in memeory pointing to same object.
    Debug.Print Duck Is FlyingDuck  'TRUE
    Debug.Print ObjPtr(Duck) = ObjPtr(FlyingDuck) 'False !!!
 
    Dim iUnk1 As IUnknown
    Dim iUnk2 As IUnknown

    'QueryInterface asking for the Default IUnknown Interfaces.
    Set iUnk1 = Duck
    Set iUnk2 = FlyingDuck
 
    Debug.Print "*****'"
    Debug.Print iUnk1 Is iUnk2  'TRUE
    Debug.Print ObjPtr(iUnk1) = ObjPtr(iUnk2) 'TRUE

End Sub


This stuff can get a bit confusing but it clears up if you keep at it.

Here is an interesting thread in VBForums where I got some good answers about this topic.

Also, you may want to take a look at these in case you haven't seen them:




 
Upvote 0
I would personally prefer to go the Interface (polymorphism) route should there be lots of *If-Then-Else / Select Cases* in my project. I think the overall design becomes more intuitve but that is just a guess.

Two things I like about implementing interfaces is the abillity to type cast and the ability to force vba intellisense to show only relevant Properties & Methods.

Consider the following example:

1- IAnimal Interface.
VBA Code:
Option Explicit

Public Sub MakeSound()
    '
End Sub

2- IBird Interface.
VBA Code:
Option Explicit

Public Sub Fly()
    '
End Sub



3- CCat Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal

Private Sub IAnimal_MakeSound()
    'Cat implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Meow!!!  Meow!!!", , "Cat"
End Sub

4- CDog Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal

Private Sub IAnimal_MakeSound()
    'Dog implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Woof!!!  Woof!!!", , "Dog"
End Sub

5- CDuck Implementation Class.
VBA Code:
Option Explicit

Implements IAnimal
Implements IBird

Private Sub IAnimal_MakeSound()
    'Dog implementation of the IAnimal Interface [MakeSound Method]:
    MsgBox "Quack!!!  Quack!!!", , "Duck"
End Sub

Private Sub IBird_Fly()
    'Duck implementation of the IBird Interface [Fly Method]:
    MsgBox "Knock Knock Knock Knock !!", , "Duck"
End Sub




Usage in Standard Module

VBA Code:
Option Explicit

Sub Interfaces_Example()

    Dim Cat As IAnimal
    Dim Dog As IAnimal
 
    Set Cat = New CCat
    Set Dog = New CDog
 
    Cat.MakeSound
    Dog.MakeSound

    Dim Duck As IAnimal
    'QueryInterface asking for the IAnimal Interface.
    Set Duck = New CDuck
    Duck.MakeSound
 
    Dim FlyingDuck As IBird
    'Casting:
    'QueryInterface asking for the IBird Interface.
    Set FlyingDuck = Duck
    FlyingDuck.Fly
 
    'Different addresses in memeory pointing to same object.
    Debug.Print Duck Is FlyingDuck  'TRUE
    Debug.Print ObjPtr(Duck) = ObjPtr(FlyingDuck) 'False !!!
 
    Dim iUnk1 As IUnknown
    Dim iUnk2 As IUnknown

    'QueryInterface asking for the Default IUnknown Interfaces.
    Set iUnk1 = Duck
    Set iUnk2 = FlyingDuck
 
    Debug.Print "*****'"
    Debug.Print iUnk1 Is iUnk2  'TRUE
    Debug.Print ObjPtr(iUnk1) = ObjPtr(iUnk2) 'TRUE

End Sub


This stuff can get a bit confusing but it clears up if you keep at it.

Here is an interesting thread in VBForums where I got some good answers about this topic.

Also, you may want to take a look at these in case you haven't seen them:




Thanks for the explanantion.

I agree this stuff can be confusing.

On a similar note, I looked into Event, RaiseEvent and WithEvents and found this video explains it clearly about being the Publisher vs the Subscriber:

Code:
https://www.youtube.com/watch?v=kfIabBuUtmA
 
Upvote 0

Forum statistics

Threads
1,224,909
Messages
6,181,672
Members
453,061
Latest member
schiefA

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top