Gambas 3/Gambas3LeLangage/L'orienté objet avec Gambas/L'héritage
L'héritage modifier
Vous faites des classes et votre code semble bien structuré. Le temps passe et vous vous rendez compte que plusieurs classes partagent du code. Vous avez le sentiment de vous répéter.
Une solution pourrait être de mettre le code partagé dans un module. Cependant quand on crée de nombreuses méthodes statiques qui prennent en argument des objets et agissent dessus on ne fait pas de la programmation orientée objet.
Le code ci-dessous n'est pas objet :
Move(car, 15, 13) ' déplace la voiture
Move(motorbike, -2, 20) ' déplace la moto
La solution est de créer une classe parente qui regroupe le code partagé en un endroit.
La relation d'héritage est caractérisée par l'expression EST UN. Si par exemple, une voiture est un véhicule et une moto aussi. Les classes Voiture et Moto héritent de la classe Véhicule.
Avec Gambas, on note simplement Inherit ClasseParente tout au début du code des classes filles comme ceci :
' Gambas Class Car
'
Inherit Vehicle
' ...
Public Sub Move(x as Integer, y as Integer)
' ...
' ...
Ceci permet d'utiliser cette méthode héritée directement sur un objet de la classe fille :
' ...
car.Move(15, 13) ' déplace la voiture
' ...
L'héritage permet aussi de spécialiser une classe. Ci-dessous, je vous donne la classe de base (ou classe parente) pour représenter un bateau :
' Gambas class file
' Boat
Private $fXPosition As Float
Private $fYPosition As Float
Private $iCap As Integer
Private $fSpeed As Float
Property XPosition As Float
Property YPosition As Float
Property Cap As Integer
Property Speed As Float
Public Sub Move()
Dim result As Boolean
Dim stopped As Boolean
stopped = ($fSpeed = 0)
If Not stopped Then
result = AvanceDroit($iCap, $fSpeed)
If Not result Then
AvanceDeTravers($iCap, $fSpeed)
Endif
Endif
End
Private Function AvanceDroit(Angle As Integer, Distance As Float) As Boolean
Dim result As Boolean = False
Select Case Angle
Case 0
$fYPosition -= Distance
result = True
Case 90
$fXPosition += Distance
result = True
Case 180
$fYPosition += Distance
result = True
Case 270
$fXPosition -= Distance
result = True
Case Else
result = False
End Select
Return result
End
Private Function AvanceDeTravers(Angle As Integer, Distance As Float) As Boolean
Dim distAdjacent As Float
Dim distOppose As Float
If Angle > 270 Then
Angle -= 270
distAdjacent = DistanceAdjacent(Angle, Distance)
distOppose = DistanceOppose(Distance, distAdjacent)
$fXPosition -= distAdjacent
$fYPosition -= distOppose
Else If Angle > 180 Then
Angle -= 180
distAdjacent = DistanceAdjacent(Angle, Distance)
distOppose = DistanceOppose(Distance, distAdjacent)
$fXPosition -= distOppose
$fYPosition += distAdjacent
Else If Angle > 90 Then
Angle -= 90
distAdjacent = DistanceAdjacent(Angle, Distance)
distOppose = DistanceOppose(Distance, distAdjacent)
$fXPosition += distAdjacent
$fYPosition += distOppose
Else
distAdjacent = DistanceAdjacent(Angle, Distance)
distOppose = DistanceOppose(Distance, distAdjacent)
$fXPosition += distOppose
$fYPosition -= distAdjacent
Endif
End
Private Function DistanceAdjacent(Angle As Integer, Distance As Float) As Float
Return Cos(Rad(Angle)) * Distance
End
Private Function DistanceOppose(DistanceHypothenus As Float, DistanceAdjacent As Float) As Float
Dim carreHyppo As Float
Dim carreAdjacent As Float
carreHyppo = DistanceHypothenus ^ 2
carreAdjacent = DistanceAdjacent ^ 2
Return Sqr(carreHyppo - carreAdjacent)
End
Private Function Cap_Read() As Integer
Return $iCap
End
Private Sub Cap_Write(Value As Integer)
$iCap = Value
End
Private Function Speed_Read() As Float
Return $fSpeed
End
Private Sub Speed_Write(Value As Float)
$fSpeed = Value
End
Private Function XPosition_Read() As Float
Return Round($fXPosition, 0)
End
Private Sub XPosition_Write(Value As Float)
$fXPosition = Value
End
Private Function YPosition_Read() As Float
Return Round($fYPosition, 0)
End
Private Sub YPosition_Write(Value As Float)
$fYPosition = Value
End
Puis j'en crée une autre pour un bateau à moteur sachant que j'aimerais bien conserver ma classe de base. Eh oui, car j'aimerais bien faire aussi une classe Voilier après ...
Ci-dessous, la classe étendue (ou classe fille) pour représenter un bateau à moteur :
' Gambas class file
' Motorboat
Inherits Boat
Public Const const_fMaxMotorboatSpeed As Float = 2.0
Public Const const_fIncreasingMotorboatSpeed As Float = 0.1
Public Const const_fDecreasingMotorboatSpeed As Float = 0.05
Public Sub Move()
Super.Move()
Me.Speed -= const_fDecreasingMotorboatSpeed
If Me.Speed < 0.0 Then
Me.Speed = 0.0
Endif
End
Public Sub Gaz()
Me.Speed += const_fIncreasingMotorboatSpeed
If Me.Speed > const_fMaxMotorboatSpeed Then
Me.Speed = const_fMaxMotorboatSpeed
Endif
End
Vous avez remarqué l'utilisation de Super
qui fait référence à l'objet issu de la classe de base et de Me
qui fait référence à l'objet en cours d'utilisation.
Avec l'héritage, vous pouvez étendre les classes. La classe fille hérite des constantes, événements, méthodes et des propriétés de la classe de base et vous ajoutez des constantes, événements, méthodes et des propriétés supplémentaires.
Avec l'héritage, vous pouvez modifier le comportement d'une classe en surchargeant les méthodes, constantes ou propriétés. Il suffit pour cela d'écrire la même méthode, constante ou propriété dans la classe fille que dans la classe mère et de créer des instructions différentes dans le code de la classe fille.
En revanche, vous ne pouvez pas enlever des propriétés, etc. Pour cela, vous devrez utiliser la composition.
Dans la pratique, l'héritage n'est pas très utilisé en Gambas mais il est utilisé de temps en temps tout de même.
Un peu perdu ? Ne vous inquiétez pas ! Avec le temps, ça viendra.