Complex type structures can be built through composition, aggregation, and inheritance.
Composition or aggregation (specialized form of association) is the process of creating more complex types from simple ones, while inheritance is the process of creating more complex type by acquiring the attributes and behaviors of existing ones.
There is a very famous design principle which says “Favor composition over inheritance“, or also "Don’t use inheritance just to get code reuse". One other reason to favor composition with FreeBASIC (as with many other languages) is it does not support multiple inheritance.
1) Definition of composition, aggregation, and inheritance
Definition:
Composition (strong association) establishes a “HAS-A” relationship between objects:
- In composition, the component object exists solely for the use of its composite object.
- If the composite object is destroyed, the component object is destroyed as well:
=> the type contains the object itself.
Aggregation (weak association) establishes a “USES-A” relationship between objects:
- In aggregation, the component object can have an existence independent of its use in the aggregate object.
- Destroying the aggregate does not destroy the component:
=> the type contains only a pointer to the object.
Inheritance establishes an “IS-A” relationship between instantiable types:
- The derived-type has the same features and functionality as its base-type, with some extensions.
Usage:
The right question to ask himself for choosing the type of relationship to use is to determine if this relationship is rather "HAS-A" or "USES-A" or "IS-A" throughout the lifetime of the application (see example below).
When user needs to use property and behavior of a type without modifying it inside its type, then association is a better option.
Whereas if needed to use and modify property and behavior of a type inside the user type, it is best to use inheritance.
2) Simple illustrative example that mixes composition, aggregation, and inheritance
Between the different types "Driver", "Person", "Driver_license" and "Vehicle", the respective relationships are:
A driver “IS-A” person (driver is a person): => "INHERITANCE".
A driver “HAS-A” driver's license (driver license only existing for the driver): => "COMPOSITION".
A driver “USES-A” vehicle (vehicle lifetime independent of the driver life): => "AGGREGATION".
Type Person
Public:
Dim As String full_name
Declare Constructor (Byref _full_name As String)
Protected: '' to forbid at compile time the default-construction attempt of a Person instance
Declare Constructor ()
End Type
Constructor Person (Byref _full_name As String)
This.full_name = _full_name
End Constructor
Type Driver_license
Public:
Dim As Integer number
End Type
Type Vehicle
Public:
Dim As String registration
Declare Constructor (Byref _registration As String)
End Type
Constructor Vehicle (Byref _registration As String)
This.registration = _registration
End Constructor
Type Driver Extends Person '' inheritance
Public:
Dim As Driver_license dl '' composition
Dim As Vehicle Ptr pv '' aggregation
Declare Constructor (Byref _full_name As String, Byref _dl As Driver_license)
End Type
Constructor Driver (Byref _full_name As String, Byref _dl As Driver_license)
Base(_full_name)
This.dl = _dl
End Constructor
'--------------------------------------------------------------------------------------------------
Dim As Driver d1 = Driver("User fxm", Type<Driver_license>(123456789))
Dim As Vehicle Ptr pv1 = New Vehicle("ABCDEFGHI")
d1.pv = pv1
Print "Person full name : " & d1.full_name
Print "Driver license number : " & d1.dl.number
Print "Vehicle registration : " & d1.pv->registration
Delete pv1
d1.pv = 0
Sleep
Person full name : User fxm
Driver license number : 123456789
Vehicle registration : ABCDEFGHI
3) Advantages of object association (composition/aggregation) over inheritance
In most cases "HAS-A" or "USES-A" relationship is more semantically correct than "IS-A" relationship.
Aggregation is more flexible than inheritance. Implementation of type can be changed at run-time by changing the component object, but this cannot be do with inheritance (behavior of base type cannot be changed at run-time).
A design based on object association usually will have less types.
It is possible to implement a pseudo "multiple inheritance" (in languages which do not support it) by composing multiple objects into one.
There is no conflict between methods/properties names, which might occur with inheritance.
4) Downsides of object association (composition/aggregation) compared to inheritance
The behavior of the system may be harder to understand just by looking at the source code, since it's more dynamic and more interaction between types happens in run-time, rather than compile time.
Association approach might require more code and time effort.
A design based on object association usually will have more objects.
I don't understand the constructor
Declare Constructor (Byref rhs As Person) (no implementation)
in type person.
Also, the plain constructor() has no implementation.
I know the plain constructor() is needed because the field is string with no initialisation.
Apart from that I follow it OK.
The Title, while *understandable* is simply *not english*. (right choose instantly *hurts* uppon reading!)
Better options:
1) How to properly choose between composition, aggregation, and inheritance, for UDTs in FB
2) How to choose the appropriate option, between composition, aggregation, and inheritance, for UDTs in FB
Last edited by MrSwiss on Jun 04, 2018 11:48, edited 2 times in total.
The two constructors (without body) are declared Protected to forbid any construction of a Person instance:
Dim As Person p '' default construction forbidden
and
Dim As Person p = d1 '' copy-construction forbidden (also from a derived object)
Note: the Person copy-constructor could be also declared Private.
Why prevent independent construction of a person object?
Also, if you simply didn't include a copy constructor wouldn't that also prevent it from happening?
Good lesson.
fxm wrote:The two constructors (without body) are declared Protected to forbid any construction of a Person instance:
Dim As Person p '' default construction forbidden
and
Dim As Person p = d1 '' copy-construction forbidden (also from a derived object)
Note: the Person copy-constructor could be also declared Private.
Yes, I see that this personal choice to ban any construction of a Person instance induces a lot of questions and which have no relation to the subject of the article.
So I simplified, and now I forbid only the default-construction (otherwise full_name not initialized).
I was aware of the concept inheritance, but I have never used it. I have used composition and aggregation, but did not know the names for it.
One would normally put the lines "Delete pv" and "d1.pv = 0" into the destructors?
Another tutorial topic (for those with less knowledge of OOP) is maybe why one want forbid certain operations. Also, why make certain member variables private. Why people make getters and setters. And when to use 'property'. For me, this is all a bit vague and often looks like a lot of code without function.
badidea wrote:Another tutorial topic (for those with less knowledge of OOP) is maybe why one want forbid certain operations. Also, why make certain member variables private. Why people make getters and setters. And when to use 'property'. For me, this is all a bit vague and often looks like a lot of code without function.
Maybe not the right place for this discussion here, but that wiki page mostly describes 'how', and the one paragraaf that addresses 'why' is missing quotations.
edit: Yesterday, you posted another link. You removed it?
edit2: Never mind, I see that a new tutorial is started