• Aucun résultat trouvé

Approches Objet de la Programmation

N/A
N/A
Protected

Academic year: 2022

Partager "Approches Objet de la Programmation"

Copied!
37
0
0

Texte intégral

(1)

État

Approches Objet de la Programmation

e Étude de Cas : les Design Patterns E Didier Verna

EPITA / LRDE

[email protected]

lrde/~didier @didierverna didier.verna in/didierverna

(2)

Plan

État

Introduction Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(3)

Plan

État

Introduction

Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(4)

Constat Initial

État

I

Design Patterns (« patrons de conception »)

I « FAQ » des problèmes de génie logiciel I Inspirés des travaux d’[Alexander, 1977]

I (Contexte **) / Problème / Solution / (Conséquences *) I

Bibliographie

I « GoF » (*) [Gamma et al., 1994] (23 patterns) I « POSA » (**)

[Bushmann et al., 1996, Schmidt et al., 2000, Kirsher et al., 2004, Buschmann et al., 2007, Buschmann et al., 2007]

I

Constat [Norvig, 1996]

« 16 of 23 patterns are either invisible or simpler in Dylan or Lisp »

(5)

Explication

État

GoF (Introduction)

« Although design patterns describe object-oriented designs, they are based on

practical

solutions that have been imple- mented in

mainstream

object-oriented programming languages […] »

« Similarly, some of our patterns are supported directly by the less common object-oriented languages. »

I

Aspect critique trop souvent oublié

(6)

Classification des patterns

État

I

GoF : créationnelles, structurelles, comportementales

I Orientée usage

I

POSA : architecturales, de conception, idiotismes

I Orientée abstraction

Idiotismes (POSA)

« An idiom is a low-level pattern specific to a programming language. An idiom describes how to implement particular as- pects of components or the relationships between them using the features of the given language. […] They address aspects of both design and implementation. »

I

Design patterns (GoF)

⇐⇒

idiotismes (POSA)

(7)

Utilisation des Design Patterns

État

I

Prêt-à-Porter du génie logiciel

I

Pour autant, pas un substitut au bon sens / à la réflexion Remarque (POSA)

« […] sometimes, an idiom that is useful for one programming language does not make sense into another. »

Exemple du « Visiteur » (GoF)

« Use the Visitor pattern when […] many distinct and unrelated opera- tions need to be performed on objects […], and you want to avoid“polluting”

their classes with these operations. »

I

Qui a dit que les « opérations appartiennent aux classes » ?

(8)

Plan

État

Introduction Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(9)

État

Cas d’École

Version C++ naïve

Porshe +paint () : void +recycle () : void

Engine +paint () : void +recycle () : void

Body +paint () : void +recycle () : void

1 1

Wheel +paint () : void +recycle () : void 4

I

Nouvelles actions : modification de la hiérarchie nécessaire

I

Duplication de code : parcours de la hiérarchie (propagation)

(10)

État

Cas d’École

Version C++ naïve

Porshe +paint () : void +recycle () : void

Engine +paint () : void +recycle () : void

Body +paint () : void +recycle () : void

1 1

Wheel +paint () : void +recycle () : void 4

I

Nouvelles actions : modification de la hiérarchie nécessaire

I

Duplication de code : parcours de la hiérarchie (propagation)

C++

void paint ()

{ std::cout << "Painting the body." << std::endl;

for (std::vector<Wheel>::iterator i = wheels_.begin ();

i != wheels_.end ();

(*i).paint ();i++) };void recycle ()

{ std::cout << "Recycling the body." << std::endl;

for (std::vector<Wheel>::iterator i = wheels_.begin ();

i != wheels_.end ();

(*i).recycle ();i++) };

(11)

Le Pattern Visiteur

État

I

Objectifs

1. Ne pas toucher à la hiérarchie de départ 2. Abstraire le parcours de la structure I

Mécanisme

I Hiérarchie de départ

I visitable (classe abstraite) I accepter des visiteurs (méthodes) I Visiteurs

I savoirvisiter (classe abstraite) … I … chaque composant (méthodes)

(12)

Le Pattern Visiteur

État

Hiérarchie de départ

VisitablePorsheComponent +accept (v : PorsheVisitor&) : void

Porshe

+accept (v : PorsheVisitor&) : void

Wheel

+accept (v : PorsheVisitor&) : void

(13)

Le Pattern Visiteur

État

Hiérarchie de départ

VisitablePorsheComponent +accept (v : PorsheVisitor&) : void

Porshe

+accept (v : PorsheVisitor&) : void

Wheel

+accept (v : PorsheVisitor&) : void

C++

struct VisitablePorsheComponent

{ virtual void accept (PorsheVisitor&) = 0;

};

struct Body : public VisitablePorsheComponent { virtual void accept (PorsheVisitor& visitor)

{ visitor.visit (*this);

for (std::vector<Wheel>::iterator i = _wheels.begin ();

i != _wheels.end ();

i->accept (visitor);i++) };};

(14)

Le Pattern Visiteur

État

Visiteurs

PorsheVisitor +visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

PaintPorsheVisitor

+visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

RecyclePorsheVisitor +visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

(15)

Le Pattern Visiteur

État

Visiteurs

PorsheVisitor +visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

PaintPorsheVisitor

+visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

RecyclePorsheVisitor +visit (w : Wheel&) : void +visit (b : Body&) : void +visit (e : Engine&) : void +visit (p : Porshe&) : void

C++

struct PorsheVisitor

{ virtual void visit (Wheel&) = 0;

virtual void visit (Body&) = 0;

virtual void visit (Engine&) = 0;

virtual void visit (Porshe&) = 0;

};

struct PaintPorsheVisitor : public PorsheVisitor { virtual void visit (Wheel& wheel) { ... };

virtual void visit (Body& body) { ... };

virtual void visit (Engine& engine) { ... };

virtual void visit (Porshe& porshe) { ... };

};

(16)

Plan

État

Introduction Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(17)

État

Cas d’École

Version Lisp naïve

porshe

engine body

1 1

wheel 4

(paint object) (recycle object)

3

Ne pas toucher à la hiérarchie de départ

Les méthodes ne font pas partie des classes

7

Abstraire le parcours de la structure

(18)

État

Cas d’École

Version Lisp naïve

porshe

engine body

1 1

wheel 4

(paint object) (recycle object)

3

Ne pas toucher à la hiérarchie de départ Les méthodes ne font pas partie des classes

7

Abstraire le parcours de la structure

Lisp

(defgeneric paint (object) ...(:method ((body body))

#| paint the body |#

(dolist (wheel (wheels body)) (paint wheel)))

(:method ((wheel wheel)) #| paint the wheel |#)) (defgeneric recycle (object)

...(:method ((body body))

#| recycle the body |#

(dolist (wheel (wheels body)) (recycle wheel)))

(:method ((wheel wheel)) #| recycle the wheel |#))

(19)

Le Pattern Visiteur

État

Hiérarchie de départ

visitable-porshe-component

porshe wheel

(accept object visitor)

Visiteurs

porshe-visitor

paint-porshe-visitor recycle-porshe-visitor

(visit object visitor)

(20)

État

Élimination des Idiotismes Statiques

I visitable-porshe-component

inutile, même en C++

I Pas robuste (oubli toujours possible)

I Pas nécessaire (méthode acceptmanquante⇒erreur)

I Note : vérification de la complétude de acceptpossible (MOP)

Retour à la hiérarchie de départ…

(defclass visitable-porshe-component () ()) (defclass wheel (visitable-porshe-component) ()) ...

(21)

État

Élimination des Idiotismes Statiques

I porshe-visitor

utile en C++

I Prototypage de accept

(accept object visitor)

(:method ((wheel wheel) (visitor porshe-visitor)) (visit wheel visitor))

(:method ((body body) (visitor porshe-visitor)) (visit body visitor)

(dolist (wheel (wheels body)) (accept wheel visitor))) ...

I

Seul le premier argument est discriminant

(22)

État

Élimination des Idiotismes Statiques

I porshe-visitor

utile en C++

I Prototypage de accept

(accept object visitor)

(:method ((wheel wheel) (visitor porshe-visitor)) (visit wheel visitor))

(:method ((body body) (visitor porshe-visitor)) (visit body visitor)

(dolist (wheel (wheels body)) (accept wheel visitor))) ...

I

Seul le premier argument est discriminant Lisp

(defclass porshe-visitor () ()) (defgeneric accept (object visitor)

(:method ((wheel wheel) (visitor porshe-visitor)) (visit wheel visitor))

...)

(defclass paint-porshe-visitor (porshe-visitor) ()) (defclass recycle-porshe-visitor (porshe-visitor) ())

(23)

État

Élimitation des Objets Visiteurs

Utilité des objets visiteurs ?

(defgeneric accept (object visitor) (:method ((wheel wheel) visitor)

(visit wheel visitor))

(defclass...) paint-porshe-visitor () ())

(defmethod visit ((wheel wheel) (visitor paint-porshe-visitor))

#| paint the wheel |#) ...

I

Sélectionner la méthode

visit

appropriée

I

Inutile dans un langage fonctionnel

Fonctions du premier ordre utilisées comme argument

(24)

État

Élimitation des Objets Visiteurs

Utilité des objets visiteurs ?

(defgeneric accept (object visitor) (:method ((wheel wheel) visitor)

(visit wheel visitor))

(defclass...) paint-porshe-visitor () ())

(defmethod visit ((wheel wheel) (visitor paint-porshe-visitor))

#| paint the wheel |#) ...

I

Sélectionner la méthode

visit

appropriée

I

Inutile dans un langage fonctionnel

Fonctions du premier ordre utilisées comme argument Lisp

(defgeneric accept (object visitor-function) ...(:method ((body body) visitor-function)

(funcall visitor-function body) (dolist (wheel (wheels body))

(accept wheel visitor-function))) ...)

(defgeneric paint (object)

(:method ((wheel wheel)) #| paint the wheel |#...) ...)

(accept porshe #'paint)

(25)

Interlude : Pertinence du Nommage

État

acceptvisit

(let ((porshe (make-instance 'porshe))) (acceptvisit porshe #'paint)

(acceptvisit porshe #'recycle))

visitmap-object

(defgeneric visitmap-object (func object) (:method (func object)

(funcall func object)) (:method (func (body body))

(funcall func body)

(dolist (wheel (wheels body)) (visitmap-object func wheel))) ...)

(26)

Mapping Automatique

État

I

Éviter de spécialiser

map-object

à la main

I

Mapper sur

object

puis sur tous ses slots Introspection par le MOP

(defgeneric map-object (func object)

(:method (func (object list)) (mapc func object)) (:method (func (object standard-object))

(funcall func object) (mapc

(lambda (slot) (map-object func

(slot-value object (slot-definition-name slot)))) (class-direct-slots (class-of object)))))

I

Nombreux autres raffinements possibles…

(27)

Plan

État

Introduction Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(28)

État

Visiteurs à État

I

C++

I Trivial (objet = état + comportement) I

Lisp

I Fonctions + état global (beurk) I Objets CLOS (beurk)

I Fermetures lexicales (tout simplement) !

Exemple : un compteur de composants

(let ((porshe (make-instance 'porshe)) (counter 0))

(map-object (lambda (obj) (incf counter)) porshe))

(29)

Spécialisation du Mécanisme de Visite

État

I

C++

I Non trivial (laissé en exercice…) I

Lisp

1. Modification temporaire (dynamique) demap-object 2. EQL-spécialization de la fonction visiteuse

Exemple : un compteur d’imbrication (I)

(let* ((porshe (make-instance 'porshe)) (depth 0)

(before (defmethod map-object :before (func object) (incf depth))) (after (defmethod map-object :after (func object) (decf depth)))) (map-object (lambda (obj)

(format t "~S, current level: ~A~%"

(class-name (class-of obj)) depth)) porshe)

(remove-method #'map-object before) (remove-method #'map-object after))

(30)

Spécialisation du Mécanisme de Visite

État

I

C++

I Non trivial (laissé en exercice…) I

Lisp

1. Modification temporaire (dynamique) demap-object 2. EQL-spécialization de la fonction visiteuse

Exemple : un compteur d’imbrication (II)

(let ((depth 0))

(defun print-depth (obj)

(format t "~S, current level: ~A~%" (class-name (class-of obj)) depth)) (defmethod map-object :before ((func (eql #'print-depth)) object)

(incf depth))

(defmethod map-object :after ((func (eql #'print-depth)) object) (decf depth)))

(let* ((porshe (make-instance 'porshe))) (map-object #'print-depth porshe))

(31)

Plan

État

Introduction Visiteurs C++

Visiteurs Lisp

Bonus : Visiteurs à État

Conclusion

(32)

Résumé

État

I

Ne pas toucher à la hiérarchie de départ : n/a

I Fonctions génériques hors-classes

I

Abstraire l’infrastructure de visite : 10 lignes

I Fonctions génériques de 1reclasse

I CLOS MOP (introspection) I

Visiteurs à État : +5-10 lignes

I Fermetures lexicales I Fonctions anonymes

I Méthodes étendues (before/after)

(33)

Conclusion

État

La « Métaphore de l’Iceberg »

(34)

Plan

Bibliographie

(35)

Bibliographie I

Alexander, C. (1977)

A Pattern Language : Towns, Buildings, Constructions

Oxford University Press

Gamma, E. and Helm, R. and Johnson, R. and Vlissides, J. (1994) Design Patterns

Addison-Wesley

Buschmann, F.and Meunier, R. and Rohnert, H. and Sommerlad, P.

and Stal M. (1996)

Pattern-Oriented Software Architecture

Wiley

(36)

Bibliographie II

Schmidt, D.C. and Stal, M. and Rohnert, H. and Buschmann, F.

Pattern-Oriented Software Architecture : Patterns for Concurrent and Networked Objects (2000)

Wiley

Kircher, M. and Jain, P. (2004)

Pattern-Oriented Software Architecture : Patterns for Resource Management

Wiley

Buschmann, F. and Henney, K. and Schmidt, D.C. (2007) Pattern-Oriented Software Architecture : A Pattern Language for Distributed Computing

Wiley

(37)

Bibliographie III

Buschmann, F. and Henney, K. and Schmidt, D.C. (2007)

Pattern-Oriented Software Architecture : On Patterns and Pattern Languages

Wiley

Norvig, P. (1996)

Design Patterns in Dynamic Programming

Object World Conference

Verna, D. (2010)

Revisiting the Visitor : the Just Do It pattern

Journal of Universal Computer Science, Vol. 16.2

Références

Documents relatifs

dialog loop. The last of these is a predefined utility object that recognizes the empty message and replies by printing a NEW LINE character in disp.. This

An important thing to note is that Perl doesn't necessarily know whether a given subroutine is a class method, an object method, or just an ordinary subroutine, so the.. programmer

By using this method in conjunction with one of the create object methods and adding a magic get method to the class you’re instantiating, it is easy to retrieve the data members

Within the development process, conceptual patterns come into play when we begin dealing with the domain concepts of the application, and when we have finished iden- tifying

Since this is the first article, I have no previous material to build from. The question is what does this program do? This is a good test of your code reading

MS-DOS File Compatibility Package (read &amp; write MS-DOS file systems on non-MS-DOS computers) CSource Application Program Generator by MBAC (includes all source code;

• For an application shared across a client and a For an application shared across a client and a server, separate code must be written for select, server, separate code must

Logical to control whether a standard latex ending is written to the output file after the document has been processed.. In its simplest form this