mercredi 10 septembre 2014

Introduction au paradigme objet et concepts avancés

Cours reformulé à partir de ce lien.

Origine

 Programmation Orientée Objet (POO) est un paradigme de programmation informatique
élaborée par Alan Kay dans les années 1970.

Un objet :
1/ un concept,
2/ possède une structure internet et un comportement,
3/ communique avec ses pairs.

La programmation par objet facilite le processus d'élaboration d'un programme.

Les outils facilitent de beaucoup la conception, la maintenance et la productivité d'une application informatique. On distingue :

- les langages de programmation (JAVA, C, C++, C#...),
- les outils de modélisation,
- les bus distribués,
- les ateliers de génies logiciels (AGL) comme Visual Studio, Eclipse...

Le langage Simula-67 pose les constructions qui seront celles des langages orienté objet à classes (classe, polymorphisme, héritage, etc.) : C++, Java, Eiffel...

Les travaux d'Alan Kay (objet, encapsulation, messages, typages, polymorphisme...) sont véhiculés par Smaltalk 71 et Smaltalk 80.

Années 80 : effervescence des langages objets (objective C, C++, Eiffel...)

Années 1990 : âge d'or de l'extension de la programmation par objet.

L'objet

 Un objet est une structure de données (– les attributs – décrivent son état) qui répond à un ensemble de messages – l'interface – (décrivent son comportement).

Selon le principe d'encapsulation, les attributs et les méthodes sont cachés. Ainsi, le programme peut modifier la structure interne des objets ou leurs méthodes associées sans avoir d'impact sur les utilisateurs de l'objet. 

L'encapsulation

Deux courants principaux.

1. Par exemple, dans Smaltalk et Eiffel : les attributs ne sont souvent disponibles qu'en lecture en général dans le programme et en écriture aussi depuis l'intérieur de la classe d'objet. On adapte ce cadre à des classes amies ou à des catégories et des hiérarchies d'objets.

2. Deuxièmement les langages tels que C++, Java ou Python et plus généralement tous les langages influencés par la syntaxe du C++ qui a proposé trois niveaux de visibilité :
  • public : les attributs dits publics sont accessibles à tous,
  • protégé : les attributs dits protégés sont accessibles seulement aux classes dérivées,
  • privé : les attributs privés sont accessibles seulement par l'objet lui-même.
Ici, pas de distinction entre l'écriture et la lecture des attributs.

Le polymorphisme 

Dans la programmation par objet, chaque objet est typé.


Le type définit la syntaxe (« Comment l'appeler ? ») et la sémantique (« Qu'est ce qu'il fait ? ») des messages auxquels peut répondre un objet.

Un objet peut appartenir à plus d'un type = polymorphisme (même code utilisé par différents types) =/= sous-typage.

Une méthode est le sous-typage : on raffine un "type-père" à un "sous-type".

Deux mécanismes de typage :
- typage dynamique : type des objets déterminé à l’exécution lors de la création des dits objets (Smalltalk, CLOS, Python, PHP, …)
- typage statique : type des objets vérifié à la compilation et est soit explicitement indiqué par le développeur lors de leur déclaration (C++, Java, C#, Pascal…), soit déterminé par le compilateur à partir du contexte (Scala, OCaml, Haskell, …).

Redéfinition

Soit un type Reel contenant une méthode * faisant la multiplication de deux nombre réels.

Soient Entier un sous-type de Reel, i un Entier et r un Reel.


Alors l'instruction i * r va exécuter la méthode * de Reel. On pourrait appeler celle de Entier grâce à une redéfinition.


- Typage de premier ordre,
- Typage de second ordre. 

Principes de bases OO

5 principes de bases pour la Programmation Orientée Objet représentés par l'acronyme SOLID doivent permettre le développement de logiciel plus fiable et plus robuste.

S
Responsabilité unique (Single responsibility principle)
une classe doit avoir une et une seule responsabilité
O
Ouvert/fermé (Open/closed principle)
une classe doit être ouverte à l'extension, mais fermée à la modification
L
Substitution de Liskov (Liskov Substitution Principle)
une classe doit pouvoir être remplacée par une instance d'un de ses sous-types, sans modifier la cohérence du programme
I
Ségrégation des interfaces (Interface Segregation Principle)
préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une seule interface générale
D
Inversion des dépendances (Dependency Inversion Principle)
il faut dépendre des abstractions, pas des implémentations

Paradigme objet (classe)

La classe :
  • décrit la structure interne des données et elle définit les méthodes qui s'appliqueront aux objets de même famille (même classe) ou type.
  • propose des méthodes de création des objets dont la représentation sera donc celle donnée par la classe génératrice.
La classe peut être décrite par des attributs et des messages. Ces derniers sont alors appelés, par opposition aux attributs et messages d'un objet, variables de classe et opération ou méthodes de classe.

Paradigme objet (réflexion)


La réflexion est la capacité d'un programme à examiner, et éventuellement à modifier, ses structures internes de haut niveau (par exemple ses objets) lors de son exécution.
On distingue deux techniques utilisées par les systèmes réflexifs :
  • l'introspection, qui est la capacité d'un programme à examiner son propre état.
  • l'intercession, qui est la capacité d'un programme à modifier son propre état d'exécution ou d'altérer sa propre interprétation ou signification.
L'introspection est utilisée pour effectuer des mesures de performance, inspecter des modules ou déboguer un programme. Elle est implémentée dans des langages comme Smalltalk, Java ou C# qui fournissent des outils pour connaître la classe d'un objet, ses attributs, ses méthodes, etc. L'introspection n'existe pas dans des langages comme C ou Pascal.

L'intercession permet à un programme d'évoluer automatiquement en fonction des besoins et de l'environnement. Cette propriété apparaît dans des langages comme SmallTalk ou Python, mais elle n'existe pas dans des langages comme C. En Java, on peut modifier l'état des objets, mais pas l'objet classe.

En programmation orientée objet, l'architecture réflexive est implémentée par le concept des métaobjets. Ceux-ci représentent des éléments des programmes orientés objets comme les classes, les messages et les fonctions génériques. La manipulation de ces métaobjets se fait par un protocole à métaobjets qui permet de décider des comportements du langage. CLOS est le premier langage à avoir implémenté un protocole à métaobjets.


Paradigme objet (réification)

La réification consiste à transformer un concept (abstrait) en un objet informatique (concret). Ce terme est surtout utilisé en programmation orientée objet ou en programmation fonctionnelle.
Par exemple, soit un objet p d'une classe Point et contenant les deux entiers 2 et 3 dans son état. p est une réification du point de coordonnées (2;3).
Lorsque le langage orienté objet possède un mécanisme de réflexion, il réifie des éléments du langage, comme :
  • les classes (on parle dans ce cas de métaclasses),
  • les objets, les liens d'héritage, les connexions entre les objets, etc. (on parle dans ce cas de métaobjets).

Paradigme objet (types de réflexion)

Il existe deux types de réflexion : la réflexion structurelle et la réflexion comportementale.

La réflexion structurelle consiste à réifier le code d'un programme et tous les types abstraits accessibles par ce programme. Dans le premier cas, la réification du code d'un programme permet de manipuler ce programme pendant l'exécution. Il est possible ainsi de maintenir un programme même lorsque celui-ci effectue des tâches. Dans le deuxième cas, la réification des types abstraits permet au programme d'examiner et de modifier la structure de types complexes. On peut ainsi, par exemple, mettre au point des algorithmes génériques de sérialisation.

La réflexion comportementale (ou réflexion de comportement) concerne plus particulièrement l'exécution du programme et l'environnement du programme. Par ce type de réflexion, un programme a moyen de savoir comment il est interprété et a la possibilité de modifier sa façon d'être exécuté, en intervenant sur les structures de données de l'évaluateur du programme et sur l'évaluateur lui-même. Ainsi, le programme peut obtenir des informations sur son implémentation ou même s'auto-réorganiser afin de s'adapter au mieux à un « environnement ».

Paradigme objet (métaclasse)
 
La classe permet de créer de nouveaux objets au moyen d'un mécanisme appelé instanciation. Ce mécanisme peut se décomposer en deux opérations :
  • allocation d'un espace mémoire pour le nouvel objet (opération alloc()),
  • initialisation du nouvel objet (lancement du constructeur).
Dans des environnements de programmation réflexifs, les classes peuvent être vues comme des objets à part entière créés au moyen du mécanisme d'instanciation (alloc(); init()). Dans ce cas, toutes les classes peuvent être vues comme des instances créées à la base à partir d'une même classe.

Une classe dont les instances sont des classes se nomme métaclasse (notez que la définition est récursive).

Puisqu'une métaclasse est une classe, elle définit elle aussi le comportement et la structure de l'état de ses instances. En créant une nouvelle métaclasse, on va donc intervenir sur la manière avec laquelle les classes sont créées et donc intervenir sur une partie du langage lui-même.

Grâce à un mécanisme comme celui-ci, le développeur peut ajouter de nouvelles fonctionnalités au langage, comme la possibilité de tracer les appels de méthodes, la possibilité de créer des singletons, la sérialisation d'objets au format XML, etc.
  Paradigme objet (prototype)

Article détaillé : Programmation orientée prototype.
 
Le prototype est un objet à part entière qui sert de prototype de définition de la structure interne et des messages. Les autres objets de mêmes types sont créés par clonage.
Dans le prototype, il n'y a plus de distinction entre attributs et messages : ce sont tous des slots.
  • Un slot est un label de l'objet, privé ou public, auquel est attachée une définition (ce peut être une valeur ou une opération).
  • Cet attachement peut être modifié à l'exécution.
  • Chaque ajout d'un slot impacte l'objet et l'ensemble de ses clones.
  • Chaque modification d'un slot est locale à l'objet concerné et n'impacte pas ses clones.
Le concept de trait permet de modifier un slot sur un ensemble de clones.
Un trait est un ensemble d'opérations de même catégorie (clonage, persistance, etc.) transverse aux objets.
  • Il peut être représenté soit comme une structure particulière du langage, comme un slot dédié ou encore comme un prototype.
  • L'association d'un objet à un trait fait que l'objet et ses clones sont capables de répondre à toutes les opérations du trait.
  • Un objet est toujours associé à au moins un trait, et les traits sont les parents des objets (selon une relation d'héritage).
  • Un trait est donc un mixin doté d'une parenté.
Parmi les langages à prototype on trouve Javascript, Self, Io, Slater, Lisaac, etc.
 

  Paradigme objet (modélisation)


La modélisation objet consiste à créer un modèle informatique du système de l’utilisateur (un système informatique).
  • Ce modèle peut rassembler aussi bien des éléments du monde réel que des concepts ou des idées propres au métier ou au domaine duquel fera partie le système.
  • La modélisation Objet consiste à définir, à qualifier dans un premier temps ces éléments sous forme de types, donc indépendamment de la mise en œuvre. C’est ce que l’on appelle l'analyse orientée objet ou OOA (Object-Oriented Analysis).
Puis, on propose une ou des solutions techniques pour représenter les éléments définis dans le système informatique. C’est ce que l’on appelle la conception orientée objet ou OOD (Object-Oriented Design).
  • Une fois un modèle de conception établi, il est possible au développeur de leur donner corps dans un langage de programmation. C’est ce que l’on appelle la programmation orientée objet ou OOP (Object-Oriented Programming).
À un modèle d’analyse peuvent correspondre plusieurs modèles de conception.


  Paradigme objet (modèles)


Pour écrire ces différents modèles, différents langages et méthodes ont été mis au point, dont OMT de Rumbaugh, BOOCH'93 de Booch et OOSE de Jacobson.
  • Toutefois, ces méthodes ne permettaient de modéliser que certains types d’applications et se trouvaient limitées dans d’autres contextes. La méthode OMT prévalait sur l’ensemble des autres méthodes dans la première partie de la décennie 1990.
À partir de 1994, Rumbaugh, Booch et Jacobson ont décidé de s’unir dans l’élaboration d’une nouvelle méthode, suffisamment générique, pour pouvoir s’appliquer à quasiment tous les contextes applicatifs.
Ils ont commencé d’abord par définir un langage de modélisation fortement inspiré de celles des méthodes des trois auteurs : UML (Unified Modeling Language).
Une fois celui-ci pris en charge par l’OMG (Object Management Group), un organisme destiné à standardiser des technologies objet, comme CORBA (Common Object Request Broker Architecture), un intergiciel (middleware en anglais) objet réparti, Rumbaugh, Booch et Jacobson se sont attaqués à la méthode proprement dite: USDP (Unified Software Development Process). Cette méthode définit un cadre générique de développement objet avec UML comme langage de modélisation.
  • USDP (généralement raccourci en UP) est une méthode itérative et incrémentale, centrée sur l’architecture et guidée par les cas d’utilisation et la réduction des risques. C’est aux concepteurs de s’attribuer cette méthode en l’instanciant à leur métier et à leur domaine.
Néanmoins pour un certain nombre de concepteurs objet, dont Bertrand Meyer, l’inventeur du langage orienté objet Eiffel, guider une modélisation objet par des cas d’utilisations est une erreur de méthode qui n’a rien d’objet et qui est plus proche d’une méthode fonctionnelle. Pour eux, les cas d’utilisations sont relégués à des utilisations plutôt annexes comme la validation d’un modèle par exemple.





Aucun commentaire:

Enregistrer un commentaire