Cours VB.NET

Image non disponible


précédentsommairesuivant

XVI-A. Diverses sortes de programmation

Programmation impérative.

Programmation structurée.

Programmation fonctionnelle.

Programmation procédurale.

Programmation évènementielle.

Programmation défensive.

Programmation Objet.

XVI-A-1. Programmation impérative

On en fait sans le savoir:

Le programmeur spécifie explicitement l'enchaînement des instructions devant être exécutées :

Fais ceci, puis cela.

Fais ceci, si cela est vrai.

Fais ceci, tant de fois .

Un programme impératif est composé de différentes instructions indiquant de manière explicite comment résoudre un problème.

On l'a déjà vu, les instructions sont effectuées de manière séquentielle:

Instruction1
Instruction2
Instruction3
...

Image non disponible

Il y a des choix:

If.. Then

Image non disponible

Il y a des boucles:

For .. next

Image non disponible

L'action de base dans la programmation impérative est l'affectation, c'est-à-dire la modification de la valeur associée à une variable du programme.

 
Sélectionnez

A=3

L'affectation va être soit effectuée en séquences successives, soit avec des choix, soit itérée selon les compositions définies par les algorithmes.

En programmation impérative, on travaille sur le modèle de la machine de Turing, avec une mémoire centrale et des instructions qui modifient son état grâce à des assignations successives.

Le langage machine et l'assembleur sont des langages impératifs. Le code en Visual Basic l'est aussi.

Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

 
Sélectionnez

10 Dim tableau (10) as Integer
20 Dim compteur As Integer
30 compteur= 0
40 boucle:
50 tableau(compteur)=0
60 compteur= compteur + 1
70 If Compteur <11 Then Goto boucle

Ici on utilise un Basic très ancien avec un goto pour faire une boucle et des numéros de ligne; c'est pas très 'lisible'.

Et c'est quoi la programmation non impérative?

C'est par exemple la programmation déclarative, elle consiste à énoncer les propriétés d'un système de résolution (à les déclarer) plutôt qu'à décrire les opérations à effectuer comme dans le cas de la programmation impérative. VB ne permet pas la programmation déclarative.

Un programme déclaratif définit (ou "déclare") différentes entités et leurs relations, à charge ensuite pour le programme d'utiliser ces relations pour résoudre le problème.

XVI-A-2. Programmation structurée

Pour éviter les programmes 'spaghetti', on a structuré et utilisé les procédés suivant:

Découpage en fonction:

L'approche structurée découpe le problème en fonctions:

L'analyse se fait de manière descendante: on découpe un problème complexe en problèmes plus simples qui sont eux mêmes découpés en problèmes plus simples. On découpe jusqu'à ne plus avoir que des problèmes simples.

Il existe aussi l'analyse ascendante: ayant à sa disposition des procédures simples, on les assemble en les faisant appeler par des procédures plus complexes pour atteindre la solution.

Si le projet est entièrement nouveau, on fait plutôt une analyse descendante; si on travaille sur un projet possédant déjà toutes les procédures simples, on raisonnera en analyse ascendante.

Rien n'empêche d'avoir une analyse mixte.

Les programmeurs doivent donc décomposer leur code en petites fonctions, assez petites pour être facilement comprises et claires.

Utilisation de variables locales:

En général les programmes doivent éviter d'utiliser des variables globales.

Au lieu de cela, les sous-programmes doivent utiliser des variables locales et agir sur des arguments ou paramètres qui leurs sont envoyés.

Organisation hiérarchique simple du code:

La programmation structurée recommande une organisation hiérarchique simple du code. Pour cela on utilise des structures de contrôles while, Do Loop, for, if .. then .. else.

Il est également recommandé de n'avoir qu'un point d'entrée pour chaque boucle (et un point de sortie unique dans la programmation structurée originelle).

Eviter les 'Goto'

L'instruction Goto, directement héritée des instructions de saut des langages machines (Jmp), était nécessaire dans les langages primitifs (Fortran, Assembleur) comme instruction de base permettant de réaliser des boucles et autres structures de contrôles (voir exemple sur la programmation impérative).

En programmation structurée (depuis les années 1970), l'instruction Goto n'est guère appréciée des programmeurs, car elle casse la structure séquentielle du programme et rend souvent les programmes plus difficiles à comprendre et à maintenir (on parle dans ce cas de programmation spaghetti). On utilise plus généralement des structures comme les sauts conditionnels (si .. alors .. sinon .. ) ou les boucles (pour, tant que, etc.)

En VB, des instructions effectuent des sauts conditionnels ou inconditionnels (If.. Then) et remplacent l'usage de l'instruction Goto; d'autres instructions ( For..Next, Do.. Loop) permettent d'élégantes boucles.

Rupture de séquence:

Il y a même des instructions qui 'cassent' élégamment les sorties de boucles; c 'est le cas des instructions comme Continue ou Exit For. L'erreur majeure de Goto, se situe dans le fait que cette instruction renvoie vers une position précédente du code (aboutissant à ce que l'on appelle le "code spaghetti"), tandis que les deux autres renvoient (le plus souvent) vers un point du code situé logiquement après la boucle qu'elles interrompent.

 
Sélectionnez

While condition
    ..Continue While
End While

Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

 
Sélectionnez

initialisetableau:
Dim tableau (10) as Integer
Dim compteur As Integer
For compteur= 0 To 10
  tableau(compteur)=0
Next compteur
Return

On crée un sous-programme nommé initialisetableau qui a la fonction d'initialiser le tableau. Il n'utilise plus de GoTo mais une boucle For Next.

Ce sous-programme était appelé par un Gosub (Gosub n'existe plus en VB.Net)

XVI-A-3. Langage fonctionnelle

C'est un language généralisant l'usage des fonctions mathématiques. En "programmation fonctionnelle", les entités sont des fonctions au sens mathématique du terme. Une fonction en appelle d'autres qui en appelle d'autres.

Le programme principal est lui-même considéré comme une fonction qui fait appel à d'autres fonctions qui elles-mêmes...

Les langages de programmation fonctionnelle dits "purs" ne proposent ni affectation de variable, ni allocation de mémoire, ni boucles. Ces deux derniers procédés sont respectivement remplacés par les allocations automatiques et l'usage intensif de la récursivité.

Exemple de langage fonctionnel: LISP. (Pas VB)

XVI-A-4. Programmation procédurale

VB en fait.

La programmation procédurale utilise des fonctions nommées 'procédure'. Une procédure, aussi appelée routine, sous-routine, méthode ou fonction (Sub et Function en VB) contient simplement une portion de code qui effectue une fonction précise.
N'importe quelle procédure peut être appelée à n'importe quelle étape de l'exécution du programme, incluant d'autres procédures ou même la procédure elle-même (récursivité).

On peut , en appelant la procédure , envoyer des paramètres.

Avantages:
  • La possibilité de réutiliser le même code à différent emplacement dans le programme sans avoir à le retaper.
  • Une façon plus simple de suivre l'évolution du programme.
  • La création d'un code plus modulaire et structuré.

Exemple: réinitialiser un tableau en donnant la valeur 0 à tous ses éléments.

 
Sélectionnez

Sub InitialiseTableau ( tableau() As Integer)
Dim compteur As Integer
For compteur= 0 To Ubount (tableau,1)
  tableau(compteur)=0
Next compteur
End Sub

Ici on utilise une procédure, une Sub qui a pour seule fonction la réinitialisation du tableau.

XVI-A-5. Programmation défensive

Se dit d'une programmation où l'on considère que le programme peut contenir des erreurs et que l'utilisateur est parfaitement malveillant et fera tout pour faire planter le programme. Ainsi donc, il faut s'en défendre.

Elle consiste à ajouter du code vérifiant systématiquement l'état du système ainsi que la valeur des paramètres des fonctions et s'assurant que le changement d'état est consistant. Si une erreur est détectée, elle sera traitée.

En premier lieu donc on vérifiera que toutes les entrées ( saisie au clavier, lecture de fichier..) sont valides pour le programme et ne contiennent pas, par exemple, une valeur pouvant provoquer une exception non gérée ultérieurement.

Pour se défendre des entrées invalides, on utilise la 'tolérance de faute':

Pour toutes entrées:
  • On teste les valeurs, on accepte uniquement les valeurs permises.
  • On gère les exceptions avec Try.. Catch.
  • On utilise les assertions.
Une entrée invalide entraîne grâce à la programmation défensive:
  • soit l'arrêt du programme (programmation défensive forte).
  • soit l'utilisation de valeur par défaut ou d'une ancienne valeur.
  • soit l'envoie à l'appelant l'indication qu'il y a une mauvaise entrée:
    • retour d'une valeur de diagnostic
    • déclenchement d'une exception chez l'appelant ( utilisation de Throw en VB dans une classe).

L'appelant, le client doit donc tester si la valeur de retour est valide ou bien gérer les exceptions qui sont retournées (solution qui semble préférable). Il devra donc traiter l'erreur.

Exemple

 
Sélectionnez

Try 
SaveFile (maFile)
Catch E As Exception
    MsgBox (Exception.Message)
End Try

XVI-A-6. Programmation sécurisée

La programmation sécurisée va au delà de la programmation défensive; Elle consiste à prendre en compte la sécurité informatique à tous les moments de la conception, de la réalisation et de l'utilisation d'un programme. Cela permet d'éviter au maximum les trous de sécurité et autres bugs.

XVI-A-6-a. Conception

Lors de la conception, il s'agit de concevoir le programme de façon modulaire et nécessitant le moins de droits utilisateurs possible. Il est préférable d'avoir plusieurs programmes de taille réduite qui collaborent entre eux, qu'un gros programme.

XVI-A-6-b. Réalisation

Ensuite, lors de la réalisation, il faut penser à bien valider les données entrées par l'utilisateur. L'idée générale et la plus importante est de ne jamais faire confiance à l'utilisateur. Ne jamais faire des hypothèses sur les entrées sans les vérifier soi-même (par exemple taille de l'entrée, signe du nombre,...)C'est la programmation défensive.

Mais on peut généraliser ce processus:
  • En testant les entrées de toutes les procedures (Préconditions)
  • En testant les sorties de toutes les procédures afin qu'elles soient conformes à ce qu'attend l'appelant (Postconditions)

On peut aussi faire de la programmation par contrat: l'appelant vérifie que les préconditions sont remplis et envoie à la procédure des 'paramètres valides'. La procédure effectue sont code et vérifie que ce qu'elle retourne est valide. Il y a contrat entre l'appelant et la procédure appelée: l'appelant vérifie les pré conditions seulement et sait qu'on lui retournera des informations valides. La procédure sait que les paramètres qu'elle recevra sont valides ; elle vérifiera la validité de ses résultats avant de les retourner.

Invariants : en plus des pré et post conditions, tous les objets inclus dans l'échange doivent être laissés dans le même état entre le début et la fin de celui-ci. Il faut s'assurer que le système entier conserve une certaine uniformité (et que l'on évite donc les effets de bords disgracieux).

XVI-A-6-c. Exécution

Enfin lors de l'exécution, il faut penser par exemple à appliquer les différentes mise à jour de sécurité lorsqu'elles sortent. Pour ce faire, il peut être pratique de la part du concepteur de l'application de proposer un système de mise à jour simplifié de l'application.

Effet de bord:
  • Il peut arriver qu'une variable dispose d'une portée qui dépasse la procédure qui la contient, ceci afin d'être accessible à partir d'autres procédures. Certaines procédures peuvent ainsi modifier une variable dans le seul but de les maintenir dans un état donné, fixé par le développeur.
    Cette capacité d'une fonction de modifier l'état d'une valeur (variable globale ou statique, argument d'une autre fonction, affichage ou écriture des données) autre que celle qu'elle renvoie définit l'effet de bord.
  • Ce mécanisme crée une sorte d'interdépendance entre les fonctions, rendant souvent plus complexe la compréhension d'un programme... D'autant que la modification d'une fonction peut dès lors avoir des conséquences inattendues sur le résultat d'autres fonctions "liées".

XVI-A-7. Programmation évènementielle

Avant VisualBasic 1 :

Programme Basic SANS programmation évènementielle :

 
Sélectionnez

10 PRINT "Donne ton nom";
20 INPUT N$
30 PRINT "Donne ton prénom";
40 INPUT P$
50 PRINT "Bonjour "; P$; " "; N$
60 END

L'exécution de ce programme conduit au résultat suivant :

C: > RUN
Donne ton nom ? LASSERRE
Donne ton prénom ? PHILIPPE
Bonjour PHILIPPE LASSERRE
C: >

Le programme affiche des informations à l'écran avec PRINT et utilise la commande INPUT lorsqu'il a besoin que l'utilisateur lui communique une information, au moyen du clavier.

Le programmeur indique la succession des lignes , leur ordre est imposé. Le programme s'arrête quand il attend une frappe au clavier puis redémarre quand l'utilisateur a validé sa réponse (en appuyant sur la touche 'Return'). On constate que l'ordre de saisie des informations est totalement déterminé par le programme. Il n'est pas question ici que l'utilisateur indique son prénom avant son nom.

Parfois pour assouplir les choses, on créait une boucle qui lisait à la volée, le clavier et qui en fonction de la touche appuyée permettait un choix.

Depuis Visual Basic 1:

En environnement graphique, l'interaction avec l'utilisateur est beaucoup plus élaborée :
  • Il y a un environnement graphique.
  • la saisie d'informations peut s'effectuer au moyen du clavier , mais aussi de champs de saisie, boutons, listes, sélecteurs, cases à cocher, menus.
  • et surtout, l'ordre d'exécution des différentes opérations n'est pas strictement déterminé à l'avance.
  • Toute action de l'utilisateur sur l'interface graphique déclenche des évènements. Si l'utilisateur clique sur un bouton l'évènement bouton.Click est déclenché.
  • Pour chaque évènement on exécute une procédure (une Sub).

Du point de vue du développeur, cela change complètement la donne : ce n'est plus lui qui décide ce que va faire l'utilisateur ! Au contraire, il doit s'attendre a priori à n'importe quelle action de la part de ce dernier.

C'est ici qu'intervient la notion de programmation événementielle : le programme est structuré non plus pour exécuter une séquence d'instructions dans un ordre prédéfini, mais pour réagir à des événements qu'il consomme l'un après l'autre.

Exemple pratique: l'utilisateur saisie son nom et son prénom, il clique sur le bouton 'Ok' ; une boite s'ouvre indiquant "Bonjour..'

Image non disponible

Pour faire ce programme, il faut dessiner l'interface utilisateur, Vb fourni les évènements et leur procédure. Il faut ensuite écrire dans la procédure correspondant à l'évènement 'Bouton1-Click' le code qui affiche 'Bonjour..'.

 
Sélectionnez

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
 Handles Button1.Click
    MsgBox("Bonjour " &amp; TextBox1.Text &amp; TextBox2.Text)
End Sub 

Il existe d'autres évènements (Form.Load; Button1.MouseDown...) qui peuvent ne pas être utilisés.

Décortiquons le code; comment cela se passe en VB?

Le composant (le bouton) doit se lier à un écouteur d'événement à qui il va déléguer le traitement de l'événement

Le traitement de l'événement est délégué à l'écouteur et l'écouteur exécute une méthode spécifique qui prend en paramètre l'événement qui s'est produit

Dans la Région " Code généré par le Concepteur Windows Form " il y a:

 
Sélectionnez

Friend WithEvents Button1 As System.Windows.Forms.Button

On crée une variable Button1 pour le bouton de commande; WithEvents indique que l'objet Button1 a des évènements.

On voit dans le code la procédure évènement Button1_Click

 
Sélectionnez

Protected Sub Button1_Click(ByVal sender As System.Object, _ 
ByVal e As System.EventArgs) Handles Button1.Click

End Sub

Le terme Handles provoque l'association d'un événement (Button1.Click situé après Handles) à un gestionnaire d'événements ( la Sub Button1_Click) il crée une délégation. Ainsi, à l'évènement Button1.Click correspond la procédure Sub Button1_Click.

la Sub pourrait d'ailleurs se nommer différemment, cela n'a pas d'importance.

Plusieurs évènement peuvent déclencher une seule Sub.

L'association d'événements aux gestionnaires d'événements se fait au moment de la compilation et ne peut pas être modifiée.

En conclusion avant la programmation évènementielle on imposait:

 
Sélectionnez

Faire ceci.
Faire cela.  
Lire le clavier
Faire ceci.
..

Avec la programmation évènementielle, c'est plutôt:

 
Sélectionnez

Si l'utilisateur tape du texte faire ceci.
Si l'utilisateur clique sur le bouton faire cela.
...
 

XVI-A-8. Programmation Objet

Les objets sont les choses physiques ou abstraits qui nous entourent. Typiquement, dans un programme de fiches de paie, le bulletin de salaire, l'employé, etc. sont des objets.

Un objet est une entité cohérente rassemblant des données et du code travaillant sur ses données.

Un logiciel est alors vu comme des d'objets communiquant par des méthodes.

Une classe peut être considérée comme un moule à partir duquel on peut créer des objets.

" Ne commencez pas par demander ce que fait le système, demandez À QUOI il le fait ! "

XVI-B. Programmation 'procédurale' ou 'objet' ?

Image non disponible

On a vu qu'on pouvait créer des programmes avec des Sub et des Functions mais aussi avec des objets. Détaillons.

XVI-B-1. L'approche procédurale

Elle découpe le problème en fonctions:

Chaque fonction effectue une tache précise. Avec l'aide de variables et de structures.

La base de la réflexion est effectuée autour des traitements. Le concepteur considère ainsi les tâches que doit accomplir le programme, en décomposant celui-ci en une série de tâches simples (approche descendante) ou en le construisant par composition de traitements (fonctions) disponibles (approche ascendante).

Il y a donc

Image non disponible

Exemple:

Calcul du salaire d'un employé. (Nombre d'heure * Taux horaire)

Il faut écrire une Fonction CalculSalaire:

 
Sélectionnez

Public Function CalculSalaire(Taux As Single, Heure As Single) As Single
    Return Taux*Heure
End Function

Pour calculer un salaire il faut appeler la fonction avec les bons paramètres.

 
Sélectionnez

Dim TauxHoraire As Single
Dim HeuresTravaillées As Single
Dim Salaire As Single
TauxHoraire=30
HeureTravaillées=70
 Salaire=CalculSalaire(TauxHoraire,HeuresTravaillées)

Pour structurer le programme, on utilise des 'Modules Standards' contenant les divers fonctions Un module contient par exemple Function CalculSalaire.

Le point d'entrée du programme est une procédure Main():

 
Sélectionnez
 
Module module1
 
Sub main()
....Créer une instance du formulaire de démarrage et l'ouvrir
End Sub
 
 
Public Function CalculSalaire(Taux As Single, Heure As Single) As Single
    Return Taux*Heure
End Function
 
 
End Module

Si on utilise des variables globales visible dans la totalité du programme (c'est à éviter), il faut les mettre dans un module standard et les définir comme Public:

Exemple: Nom du programme et version du programme.

Exemple nom et version du programme:

 
Sélectionnez

Module module1
Public nomProgramme As String= "Calcul Salaire"
Public versionProgramme As String= "1.2"
....
 
End Module

Ainsi le nom du programme et sa version sont accessibles partout:

Dans un formulaire on peut afficher le nom du programme dans la barre supérieure.

 
Sélectionnez

Me.Text= nomProgramme

Cette accessibilité semble un avantage, en fait c'est dangereux: n'importe quelle procédure peu modifier les données.

Pour structurer les données, on peut utiliser les Structures.

Exemple: créons une structure 'Salarié'

 
Sélectionnez

Structure Salarié
Public Nom As String
Public TauxHoraire As Single
Public HeuresTravaillées As Single
End Structure

Ensuite pour avoir 100 salariés

 
Sélectionnez

Dim Salaries(100) As Salarié

On pourra utiliser Salaries(1).Nom ou Salaries(2).TauxHoraire

On verra plus loin qu'utiliser des variables dites 'globales'( visible partout) n'est pas une bonne chose, il vaut mieux créer des procédures d'accès aux données.

Plutôt que d'écrire Salaries(1).Nom="Lulu" il est préférable d'écrire une procédure SalariesAdd() qui ajoute un salarié avec son nom dans le tableau.

XVI-B-2. Approche Objet

Elle est centrée sur les Objets (et non sur les taches).

Elle nécessite de créer une Classe (le moule).

Avec l'aide de la classe on peut déclarer des objets.

Chaque Objet à des propriétés, des méthodes.

Image non disponible

Exemple:

Calcul du salaire d'un employé. (Nombre d'heure * Taux horaire)

Il faut écrire dans un module de Class une Class Employé:

 
Sélectionnez


Public Class Employé
Private T As Single     'propriétés privées à la classe pour stocker les heures et taux horaires
Private H As Single
 
Public Property Taux As Single 'propriété Taux
Get
    Return T
End Get
Set(By Val Value)
    T=value
End Set
End Property
 
Public Property Heure As Single 'propriété heure
Get
    Return H
End Get
Set(By Val Value)
    H=value
End Set
End Property
 
Public Property Salaire As Single 'méthode Salaire
Get
    Return T*H
End Get
End Property
End Class

Pour calculer un salaire il faut créer un objet Employé,donner les bonnes valeurs aux propriétés et appeler la méthode salaire.

 
Sélectionnez

Dim UnEmployé As new Employé
UnEmployé.Taux=30
UnEmployé.Heure=70
 Dim Salaire As Single =UnEmployé.Salaire

On voit donc qu'il faut créer des 'Modules de Classe' pour y mettre les nouvelles classes.

On évitera les modules standards qui ne sont pas dans l'esprit 'Objet'.

Le point d'entrée du programme pourrait être une Classe statique (Classe ne nécessitant pas d'instancier un objet):

 
Sélectionnez

Public Class main2
Public Shared Sub main()
...
End Sub
End Class

Si on utilise des variables qui doivent être accessibles, il faut les mettre dans une Classe et les définir comme Shared: Ainsi une variable partagée d'une classe (Shared) a non seulement une valeur commune à toutes les instances de la classe, mais en plus on peut travailler directement sur la Classe (sans instancier):

Exemple nom et version du programme:

 
Sélectionnez

Class MonProgramme
Public Shared nomProgramme As String= "Calcul Salaire"
Public Shared versionProgramme As String= "1.2"
....
 
End Class

Ainsi le nom du programme et sa version sont accessibles partout:

Dans un formulaire on peut afficher le nom du programme dans la barre supérieure.

 
Sélectionnez

Me.Text= MonProgramme.nomProgramme
 

On peut créer une classe qui hérite des propriétés d'une autre classe:

Dans notre exemple en programmation Objet, on créera une Class 'Patron' qui hérite de la classe 'Employé', mais dont la méthode Salaire sera redéfinie ( Overrides ). (En programmation procédurale il faudra écrire une nouvelle fonction SalairePatron).

 
Sélectionnez

 
Public Class Patron
Inherit Employé

Public Property  Overrides  Salaire As Single 'méthode Salaire
Get
    Return T*H
End Get
End Property
End Class

Pour gérer un ensemble, un groupe de données, on utilise une classe encapsulant une collection privée d'objets voir chapitre 5-7.

 
Sélectionnez

Public Class LesEmployes
     Private maCol As ArrayList

     Public Sub New()
          maCol = New ArrayList()    'cela crée une ArrayList
     End Sub


     Public Function Add(ByVal LEmploy As Employe) As Employe     
      ...
     End Function

     Public Property Item(ByVal lIndex As Integer) As Employe 
     ...     
     End Property

     
End Class

On rappelle que les classes peuvent contenir des méthodes, des variables publiques ou privées, mais elles sont 'PAR REFERENCE'

Les partisans de la programmation Objet auront tendance à utiliser exclusivement les classes du Framework plutôt que les instructions de Microsoft.VisualBasic dans leur code.

XVI-B-3. Conclusion

La programmation fonctionnel se focalise sur les actions à effectuer, alors que la programmation Objet se focalise sur les données.

La méthode procédurale est plus intuitive, on a l'impression d'être plus proche de la réalité 'physique', le code est probablement plus rapide.

L'emploi d'objet permet une abstraction plus importante, une puissance inégalée grâce à l'héritable, aux surcharges.

On peut être puriste et ne programmer qu'en procédurale ou ne programmer qu'en objet.

Visual Basic permet de mélanger les 2 approches.

XVI-C. Programmation 'procédurale' : faire de bonnes procédures

Image non disponible

Quand on fait de la programmation procédurale: on n'utilise pas de classe mais des modules standards, des Sub et des Functions.

Suivant quelles règles découper son programme?

Si on programme depuis longtemps, on le sait de manière 'intuitive' (après de nombreuses erreurs); il est tout de même intéressant de connaître les grandes règles à suivre. Très peu de sites ou d'ouvrages en parlent!!

Analyse ascendante, descendante?

Pourquoi découper en procédures?

La cohésion doit elle être importante?

Le couplage doit-il être modéré?

Comment utiliser les paramètres?

Sub ou Function?

Programmation défensive?

XVI-C-1. Approche procédurale, analyse 'descendante' ou 'ascendante'

L'approche procédurale découpe le problème en fonctions (ou procédures):

L'analyse se fait de manière descendante: on découpe un problème complexe en problèmes plus simple qui sont eux mêmes découpés en problèmes plus simples. On découpe jusqu'à ne plus avoir que des problèmes simples.

Il existe aussi l'analyse ascendante: ayant à sa disposition des procédures simples, on les assemble en les faisant appeler par des procédures plus complexes pour atteindre la solution.

Si le projet est entièrement nouveau, on fait plutôt une analyse descendante; si on travaille sur un projet possédant déjà toutes les procédures simples, on raisonnera en analyse ascendante.

Rien n'empêche d'avoir une analyse mixte.

On rappelle:

Chaque procédure effectue une tache précise.

Les procédures sont composées des ' Sub ' et des ' Function '.

Une procédure est un ensemble d'instructions, de lignes de code , un groupement d'instructions bien définies effectuant une tache précise.

Les procédures 'Sub':

Elles débutent par le mot Sub et se terminent par End Sub.

Exemple:

 
Sélectionnez

Sub MaProcédure()
   A=1
End Sub

Pour appeler la Sub:

 
Sélectionnez

MaProcedure()

Les procédures 'Function':

Les 'Function' retournent une valeur.

Elles débutent par Function et se terminent par End Function.

Exemple:

 
Sélectionnez

Function SurfaceCercle( Rayon as Single)
    Return 3.14*Rayon*Rayon        'Return indique ce que la fonction doit retourner 
End Function

Dans la procédure qui appelle, il faut une variable pour récupérer la valeur retourner par la Fonction:

 
Sélectionnez

S= SurfaceCercle()

On rappelle que le nom de la procédure doit être en minuscule avec la première lettre de chaque mot en majuscule.
SurfaceCercle() est correct.

XVI-C-2. Pourquoi utiliser des procédures ?

D'abord , dans certains cas, c'est obligatoire!! Il y a les procédures évènements automatiquement crées par VB. Ensuite, dès que l'on veut écrire du code, il faut créer des procédures Sub ou Function dans les modules de formulaire ou dans les modules standard (voir 5-10)

La programmation procédurale avec découpage en procédures a des avantages:
  • On évite la répétition du même code:

    Si il faut 30 lignes de code pour faire un calcul et que le calcul est effectué 10 fois dans le programme, il est pratique de créer une Sub CalculTotal() contenant les 30 lignes de calcul et d'appeler 10 fois la Sub.

    Voici la Sub:

     
    Sélectionnez
    
    Public Sub CalculTotal()
    A=B+C
    D=E+3
    ..
    End Sub 

    Voici les appels:

     
    Sélectionnez
    
    CalculTotal()
    ..
    CalculTotal()
  • On simplifie les modifications:

    S'il y a une modification à faire dans le calcul, la modification est effectuée 1 fois (Avec 10 fois le code du calcul disséminé dans le programme, on risque d'oublier de modifier un des codes).

  • On introduit une abstraction qui clarifie le code:

    CalculTotal() est plus compréhensible que A=B+C....

    On oublie le code interne à la procédure, pour ne plus se souvenir que de la fonction de la procédure: La procédure fait le Calcul du total..

    On masque ainsi l'implémentation.

  • On réduit la complexité:

    Chaque tache complexe est décomposée en plusieurs procédures qui elles-mêmes sont décomposées en procédures plus simples.

  • On améliore la portabilité:

    On isole dans les procédures le code non portable et on le groupe.

    Si on doit effectuer un changement (changement de type de base de données par exemple en modifiant un programme pour qu'il fonctionne sous MySQL alors qu'il fonctionnait sous Acces), il suffit de modifier uniquement les procédures d'accès à la base de données.

  • On peut masquer certaines fonctions:

    Certaines fonctions sont complexes et leur code est peu intéressant, une fois écrite il faut mieux ne plus la voir. (fonction booléens complexes)

XVI-C-3. La 'cohésion' de la procédure doit être importante

La 'cohésion' fait référence aux liens établis entre les opérations de la procédure DANS la procédure.

Un exemple:

La Sub Carré() à une forte cohésion: elle est entièrement consacrée à une tache: le calcul du carré d'un nombre.

La Sub CarréEtCube() qui calcul le carré ou le cube d'un nombre a une cohérence faible!! (Il vaut mieux dans ce cas écrire une procédure Carré() et une procédure Cube() )

Compris?

Si la cohésion est faible , il a été prouvé que les procédures contenaient plus d'erreurs de programmation.

Donc une procédure ne doit faire qu'une seule chose.

  • On parle ici de cohésion fonctionnelle: la fonction de la procédure est unique.

    EffaceFichier(), CalculAge() ont une bonne cohésion fonctionnelle, SaisirDate&CalculAge() a une moins bonne cohésion.

Il existe d'autres sortes de cohésion:
  • La cohésion temporelle:

    Différentes opérations qui n'ont rien a voir entre elles doivent être effectuées au même moment:

    Exemple: La Sub Demarrage() appelée au début d'un programme va ouvrir les fichiers, initialiser les variables, lire le fichier de configuration.

  • La cohésion séquentielle:

    Lorsque les opérations qui n'ont rien à voir entre elles doivent impérativement être effectuées dans un ordre précis:

    Exemple: La Sub CalculAnnéeRetraite() qui a partir de la date de naissance va calculer l'age puis l'année de retraite. (On pourrait aussi dans ce cas écrire une routine CalculAge() qui serait appelée par CalculAnnéeRetraite() )

Certaines cohésion sont à éviter:
  • La cohésion de communication:

    Les opérations travaillent sur les mêmes données mais n'ont pas de relation.

    ImprimeAndEffaceTableau() me parait à éviter: écrire les procédures ImprimeTableau() et EffaceTableau()

D'autres sont à bannir:
  • La cohésion logique:

    La sélection des opérations (sans relation entre elles) à effectuer est pilotée par un paramètre.

    Seul le paramètre est commun!!

    La Sub ImprimerTableauAfficherResultat (Flag) ou le Flag indique s'il faut imprimer ou afficher est à bannir.

XVI-C-4. Le 'couplage' entre procédures doit être modéré

Le couplage traite des connexions entre les différentes procédures, il doit être modéré, ce qui signifie qu'il doit y avoir peu de connexions.

  • Une procédure doit ne communiquer qu'avec un nombre " minimum " d'autres procédures du logiciel. L'objectif est de minimiser le nombre d'interconnexions entre les procédures. L'intérêt de cette règle est de garantir un meilleur respect de la protection des procédures.
  • Lorsque deux procédures communiquent entre elles, l'échange d'information doit être minimal. Il s'agit de minimiser la taille des interconnexions entre modules.

    Eviter le tout 'variables globales'.
    Une Sub ayant 2 paramètres c'est bien, une Sub en ayant 15 c'est trop.

  • Lorsque deux procédures communiquent, l'échange d'information doit être explicite:

    Eviter qu'une variable soit visible dans une procédure, alors qu'elle est déclarée dans une autre.
    Si vous modifié des variables globales utilisées par un autre module c'est dangereux!!
    Si vous utilisez un paramètre pour passer une données, c'est explicite, c'est Ok.

  • Toute information dans une procédure doit être répartie en deux catégories : l'information privée et l'information publique. Ce principe permet de modifier la partie privée sans que les clients (fonctions utilisant cette procédure) soient confrontés à un quelconque problème à cause de modifications ou de changements.

    Plus la partie publique est petite, mieux c'est..
    On déclarera en début de procédure des variables privées, et on travaillera sur ses variables privées; seul le résultat sera accessible de l'extérieur.

Une procédure doit donc être autonome:

Une procédure est autonome et ne doit pas lire ni modifier directement les variables du programme qui l'appelle, sans passer par des paramètres.

XVI-C-5. Squelette d'un programme

Exemple simpliste de l'agencement des procédures:

De manière générale, le programme est composé de procédure, en appelant d'autres, qui en appelle d'autres..

'Squelette' de programme:

 
Sélectionnez
 
Sub Démarrage
    OuvrirFichier()
    LireConfig()
    InitialiserVariable()
    LireDonnées()
End Sub
 
Sub Quitter
        EnregistrerDonnée()
        FermerFichier()
End Sub

Voici la Sub Main(), procédure de démarrage du programme :

 
Sélectionnez

Sub Main()
    Démarrage()
    'puis affiche le formulaire principal
End Sub
 

Dans le formulaire principal, un bouton 'Quitter' déclenche la Sub suivante:

 
Sélectionnez

Sub BoutonQuitter_Click(..)
    Quitter()
End Sub
 

Un bouton 'Nouveau' (travail sur de nouvelle données) contient:

 
Sélectionnez

Sub Nouveau_Click(..)
       EnregistrerDonnée()
       InitialiserVariable()
End Sub
 

On remarque que EnregistrerDonnée() et InitialiserVariable() sont appelés de plusieurs endroits.

Ensuite il suffit d'écrire tous le code des Sub.

XVI-C-6. Les paramètres

Dans quel ordre les mettre?

Une Sub reçoit 3 paramètres: P1 qui est une donnée qu'utilise la Sub, P2 qui est modifié par la Sub , P3 qui contient un résultat retourné par la Sub.

Et bien il est conseillé de les mettre dans l'ordre P1, P2, P3 (Entrée, Modification, Sortie)

Exemple Sub CalculCarré(nombre, carré) 'quand on appelle cette Sub on envoie un nombre, on récupère le carré.

S'il y a une variable d'erreur ou d'état, la mettre en fin.

 
Sélectionnez

        Sub Divise(Nombre1, Nombre2, CalculImpossible) 

'cette routine calcule Nombre1/Nombre2 mais retourne CalculImpossible=True si Nombre2 est égal à zéro.

Nombre de paramètres?

7 maximum, au delà de 7 on s'y perd!!

Dans les 7, il peut y avoir des tableaux.

Paramètres pour plusieurs routines:

Si plusieurs routines utilisent les mêmes paramètres, les mettre dans le même ordre.

AfficheText(LeTexte, Couleur) et ImprimeText(LeTexte, couleur) sont cohérent.

Ne pas utiliser de paramètre comme variable de travail.

 
Sélectionnez

Sub calcul (A, B)
A=A+2                    Est à éviter: le paramètre A ne contient plus la valeur d'entrée!!
...                      car on a utiliser A comme variable de travail.
End Sub
 

Faire plutôt:

 
Sélectionnez

Sub calcul (A, B)
Dim V As Integer= A      'On passe la valeur du paramètre dans une variable locale.
V=V+2                    'C'est mieux! A contient toujours la valeur d'entrée.
...
End Sub
 

Il faut donc déclarer en début de Sub des variables locales propres à la Sub et travailler avec elles dans la Sub.

Mettre des commentaires en début de sub:

 
Sélectionnez

Sub Divise(Nombre1, Nombre2,Resultat, CalculImpossible)
'***Division de 2 Nombres
'Entrée: Nombre1, Nombre2 de type Single
'Sortie: Résultat de type Single
'Teste Nombre2 si =0 retourne CalculImpossible=True
If Nombre2= 0 then
    CalculImpossible=True: Exit Sub
End If
Resultat=Nombre1/Nombre2
End Sub
 

Tester la validité des paramètres en début de Sub:

Voir l'exemple précédent

 
Sélectionnez

If Nombre2= 0 then    'teste le paramètre Nombre2 et quitte la Sub s'il n'est pas valide. 

C'est mieux de le faire au début pour tous les paramètres plutôt que de le faire dans toute la procédure.

XVI-C-7. Utiliser une 'Sub' ou une 'Function' ?

Les puristes diront qu'il faut utiliser une fonction quand on a une valeur de sortie (une seule).

Plusieurs paramètres d'entrée sont possible par contre.

Exemple:

La fonction FileExist(), avec comme entrée le nom d'un fichier, retourne uniquement un Booléen (True ou False), c'est bien une fonction qu'il fallait utiliser.

On peut élargir la définition en employant une fonction quand l'objectif principal est de retourner la valeur indiquée dans le nom de la fonction:

MetAuFormat( In, Out) transforme le texte 'In' en 'Out'; si la fonction à échoué elle retourne False.

On l'utilisera comme cela:

 
Sélectionnez

If MetAuFormat(In, Out) = True Then  LeText.Text=Out

On aurait pu utiliser une Sub, avec comme troisième paramètre une variable indiquant le succès ou l'échec.

 
Sélectionnez

MetAuFormat( In, Out, Succes)

Certains utilisent des noms de variable commençant par Is afin d'indiquer clairement que c'est une fonction et ce qu'elle retourne:

IsOpen() pour voir si un fichier est ouvert (retourne True si le fichier est ouvert). ce qui permet d'utiliser:

 
Sélectionnez

If IsOpen("monfichier") Then...
 

XVI-C-8. Programmation défensive

C'est comme quand on conduit une voiture; il faut se méfier des autres: bien regarder aux croisements et ralentir, même si on a la priorité!!

Il faut donc:

Tester la validité des paramètres en début de Sub:

On l'a déjà vu:

If nombre2= 0 then 'teste le paramètre Nombre2 et quitte la Sub s'il n'est pas valide ce qui évite une division par zéro si l'expression nombre1/nombre2 est utilisée.

C'est mieux de le faire au début pour tous les paramètres plutôt que de le faire dans toute la procédure.

Il faut le faire surtout si les données viennent de l'"extérieur": fichier, réseau.

Il faut encore plus le faire si c'est l'utilisateur qui a saisi les données.

Vérifier si la données est dans la plage attendue:

Si on attend le numéro d'un jour du mois, vérifier que c'est un nombre, s'il est positif, compris entre 1 et 31, entier..

Vérifier si la données est une String valide:

Si on attend un nom de fichier, vérifier que c'est du texte, éliminer les espaces en début et fin, y a t-il une extension? des caractères invalides?

En VB il y a des fonctions qui font cela.

Tester la validité des paramètres de sortie:

Prendre en charge les erreurs:

Il y a des procédures 'tolérantes':

  • Si une valeur n'est pas valide, on peut donner une valeur par défaut, redonner la précédente valeur..
  • C'est le cas des prises de température à une fréquence importante. S'il manque une valeur; reprendre la précédente.

Il y a des procédures 'strictes', cela entraîne une des actions suivantes:

  • L'arrêt du programme!!
  • La procédure redemande la valeur.
  • Elle retourne une variable indiquant qu'elle a échoué

Pendant le développement utiliser les assertions

C'est une manière de se contrôler soi-même en cours de développement.

On place des assertions dans le code:

Si elles sont vraie c'est que cela se passe comme prévu.

Si elles sont fausses c'est qu'une erreur inattendue, inacceptable se produit.

Debug.Assert affiche une fenêtre Windows et stoppe le programme si une assertion(une condition) passe à False.

 
Sélectionnez

Debub.Assert(Assertion)
Debub.Assert(Assertion, Message1)
Debub.Assert(Assertion, Message1, Message2) 

L'exemple suivant vérifie si le paramètre 'type' est valide. Si le type passé est une référence null (Nothing dans Visual Basic), Assert ouvre une boite de dialogue nommé 'Echec Assertion' avec 3 boutons 'Abandonner, Recommencer' 'Ignorer'.. La liste des appels est affichée dans la fenêtre (procédure en cours en tête de liste, module et numéro de ligne en première ligne)

 
Sélectionnez

Public Shared Sub UneMethode (type As Type, Typedeux As Type)
Debug.Assert( Not (type Is Nothing), "Le paramètre Type est=Nothing ", _
 "Je ne peux pas utiliser un Nothing")
....
End Sub UneMethode

Il n'est pas souhaitable que l'utilisateur puisse voir les messages des assertions, elles disparaissent dans le code de production.

En résumé: Une procédure doit avoir:

  • de la modularité: un sous-programme réalise une tâche et une seule (par exemple, une fonction de calcul ne doit pas afficher de résultat) ;
  • de l'autonomie: un sous-programme est autonome et ne doit pas lire ni modifier directement les variables du programme qui l'appelle, sans passer par des paramètres ;
  • de la transparence: un sous-programme doit être conçu de façon à ce que le programmeur qui y fait appel (non nécessairement son concepteur) n'ait pas à tenir compte des choix du concepteur ;
  • de la convivialité: l'appel du sous-programme doit être la plus évidente possible.

XVI-D. Programmation 'objet' : faire de bonnes Classes

Ce chapitre tente de clarifier mes connaissances, ne pas hésiter à critiquer et me donner des conseils.

Quand on programme avec une approche Objet, on crée des classes, on n'utilise par de modules standard ni de Sub et de Fonction.

Quelles règles suivre pour créer des objets?

Si on programme depuis longtemps, on le sait de manière 'intuitive' (après de nombreuses erreurs); il est tout de même intéressant de connaître les grandes règles à suivre. Très peu de sites ou d'ouvrages en parlent!!

Comment faire de bonnes Classes?

Comment bien utiliser l'héritage?

XVI-D-1. Rappel

On rappelle: Une Classe sert à créer (instancier) des objets.

En programmation Objet, dans un module de Classe, on crée la Classe:

 
Sélectionnez

Classe MyClasse
..
End Class
 

puis dans le corps du programme, on crée un objet:

 
Sélectionnez

Dim MonObjet As New MyClasse.

XVI-D-2. Pourquoi utiliser 'Classe' et 'Objet' ?

Ils permettent:

Modélisation des objets réels.

Le programme travaille avec des objets réels: une facture, un client.

Créer une classe par objet puis:

  • Y mettre les données liées à l'objet (le nom, l'adresse du client)
  • Y ajouter les méthodes contenant le comportement de l'objet (Calcul de la facture)

Modélisation des objets abstraits.

Dans un programme de comptabilité, les classes 'technicien' , 'ouvrier', dirigeant' sont concrètes; une classe 'Salarié' est plus abstraite. Les 3 premières pourront hériter de cette dernière.

Autre exemple classique: Les classes Line, Triangle sont concrètes, la classe Shape (forme en français) est abstraite, ici aussi Line et Triangle hériterons de Shape

Il existe même des Classes abstraites: Un Classe abstraite est une Classe qu'on ne peut pas instancer, elle sert uniquement à définir des caractéristiques de base pour créer des classes qui seront dérivées de la Classe abstraite.

Facilité pour réutiliser le code.

Une fois crées, les Classes servent de briques pour construire un nouveau projet.

L'héritage permet la création de nouvelle Classe héritant d'une autre.

Réduction et isolement de la complexité.

Une tache complexe est découpée en plusieurs Classes.

Masquage de l'implémentation

Un fois la Classe créée, il faut oublier les détails et l'utiliser sans connaître son fonctionnement interne.

C'est l'encapsulation.

Masquage des données globales.

Si vous devez absolument utiliser des données globales vous les masquez derrière une interface de classe.

XVI-D-3. Identifier les objets

Identifier les Objets pour définir ensuite les classes:
  1. On identifiera les objets nécessaire et leurs attributs (méthodes, données)

    Exemple:

    Système de facturation:

    Objet:ClientObjet:FactureObjet: FicheHoraire
    NomClient
    Adresse
    Date
    NomClient
    Montant
    Date
    NonClient
    NombreDheure
    TauxHoraire
     CalculerFacture()
    ImprimerFacture()
     
  2. Déterminer ce que l'on peut faire avec chaque objet:

    Exemple:

    Modifier l'adresse du Client.

  3. Déterminer ce que chaque objet peut faire aux autres objets

    Une facture peut contenir plusieurs fiches horaires.

    Un Objet peut en hériter d'un autre.

  4. Déterminer les parties visible (l'interface publique)
  5. En conclusion, pour chaque objet il faut définir:
  6. Définir l'interface utilisateur :
  7. Identifier les requêtes (information demandée à la classe); Ce sont les Property
  8. Identifier les commandes (procédures): Ce sont les méthodes. Sub ou Function
  9. Identifier les contraintes (pré-, post-condition).
  10. Définir les constructeurs. Sub New()
  11. Choisir une représentation de l'information (attributs).
  12. Implanter les fonctions, procédures et opérateurs.
  13. Définir (si nécessaire) le constructeur de copie, le destructeur

XVI-D-4. Faire un 'couplage' modéré

Le couplage traite des connexions entre les différentes Classes, il doit être modéré, ce qui signifie qu'il doit y avoir peu de connexions.

  • Une Classe doit ne communiquer qu'avec un nombre " minimum " d'autres Classes du logiciel. L'objectif est de minimiser le nombre d'interconnexions entre les Classes. L'intérêt de cette règle est de garantir un meilleur respect de la protection des Classes.
  • Lorsque deux Classes communiquent entre elles, l'échange d'information doit être minimal. Il s'agit de minimiser la taille des interconnexions entre Classes.

    Un classe qui possède 4 méthodes Public c'est mieux qu'une Classe qui en possède 15.

    Il faut donc réduire l'accessibilité des classes et des membres.

  • Lorsque deux Classes communiquent, l'échange d'information doit être explicite:
  • Toute information dans une Classe doit être répartie en deux catégories : l'information privée et l'information publique. Ce principe permet de modifier la partie privée sans que les clients (fonctions utilisant cette classe) soient confrontés à un quelconque problème à cause de modifications ou de changements. Plus la partie publique est petite, mieux c'est...

XVI-D-5. Conserver une bonne abstraction et une bonne cohérence

Une classe qui:

  • met en forme les données.
  • qui initialise le programme.
  • qui imprime un rapport.

n'est pas cohérente.

Une classe qui:

  • Initialise une donnée
  • Charge une donnée
  • Sauve une donnée

est cohérente.

De plus l'abstraction est constante: elle se situe au même niveau (celui d'une donnée); si on rajoutait dans la classe une fonction effectuant une recherche dans une liste de données cela ne serait plus le cas.

XVI-D-6. Créer des méthodes par paires

Une méthode doit entraîner l'écriture de la méthode contraire.

Activation/désactivation.

Ajout/Suppression...

Si il existe la méthode 'AddLine' , on aura forcement besoin de 'RemoveLine'.

XVI-D-7. L'encapsulation doit être bonne

L'encapsulation est une barrière qui empêche l'utilisateur de voir l'implémentation..

Il ne faut pas exposer les données:

Eviter les variables Public, directement accessibles par l'utilisateur de la Classe.

 
Sélectionnez

Class MaClasse
Public X As Single
..
End Class

C'est pas génial!!

 
Sélectionnez

Class MaClasse
Private mX As Single
Public Property X() as Single
Get
    Return mX
End Get
Set(By Val Value)
    mX=value
End Set
End Property
..
End Class

C'est mieux , l'utilisateur n'a pas accès directement à 'mX', l'utilisateur voit 'X', il peut modifier X ce qui entraîne une modification de mX mais sous contrôle, on peut même rajouter des conditions qui seront testées avant de modifier mX.

XVI-D-8. Initialisez les données dans le constructeur d'une Classe

Il est important de ne pas oublier d'initialiser les variables dans une classe, le moment idéal est quand on crée une instance de cette Classe.

 
Sélectionnez

Class MaClasse
Private mX As Integer
 
Sub New()
    mX=2
End sub
End Class 
 

XVI-D-9. Problèmes liés à l'héritage

Ne pas multiplier les classes dérivées:

Si on a une Classe 'Animal', on peut créer les classes 'Cheval' et 'Poisson' qui dérivent de la Classe 'Animal'.

Par contre il ne faut pas créer les classes 'PoissonRouge' ou 'ChevalNoir' car la couleur est plus un attribut d'une classe qu'un déterminant de Classe.

Eviter trop de classe intermédiaire:

Si 'Cheval' dérive de 'Mammifèreà4Pattes' qui dérive de 'Mammifère' qui dérive d'Animal', c'est lourd!! surtout si 'Mammifèreà4Pattes' et 'Mammifère' sont des classes abstraites qui ne seront pas instanciées.

Eviter l'héritage de construction:

Eviter de dériver une Classe en ajoutant des attributs qui modifie le concept de la classe mère.

Une classe 'Triangle' peut dériver de 'Polygone', la classe 'Carré' peut difficilement dériver de 'Triangle' (En y ajoutant les attributs d'un quatrième point!!)

Un Carré est un Polygone,oui. On ne peut pas dire qu'un Carré est un Triangle avec un sommet de plus!!

Bien comprendre la différence entre héritage et agrégation:

Comme on l'a vu dessus, quand une classe dérive d'une autre, on peut dire que la classe dérivée 'est une' classe mère.

'Carré' est un 'Polygone'

Par contre 'Carré' est composé de 4 'Point' (possède 4 points): un objet 'Carré' contient 4 objets 'Point'. On parle d'agrégation (ou de composition pour certains).


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.