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.