OVH Cloud OVH Cloud

Re: méthode find_closest

2 réponses
Avatar
oliv
Tu connais le pattern Composit
non justement et je n'ai rien trouvé de clair sur le net pour m'éclairer sur ça
tu peux m'expliquer ou me donner des liens vers des exemples simples
merc

--
oliv

-----------------------------------------------------------------------
Voir theme: http://www.frbox.net/viewtopic-531634.htm

Envoyé de http://www.frbox.ne

2 réponses

Avatar
bruno at modulix
oliv wrote:

(NB : xpost et fu2 *fr.comp.objet*)

Tu connais le pattern Composite
non justement et je n'ai rien trouvé de clair sur le net pour m'éclairer sur ça.


Ah ? (...) Mouais, effectivement, c'est moyen faible...

tu peux m'expliquer ou me donner des liens vers des exemples simples.


Le mieux serait probablement de t'acheter le GoF (un des rares bouquins
d'informatique qui vaille l'investissement).

Rapidement: le but de ce pattern est de manipuler de façon uniforme des
objets 'simples' (feuilles) et des objets 'composés' (noeuds) (nb : oui,
c'est une arborescence...). Ces deux types d'objet présentent une
interface commune (spécifique à l'application of course). Les objets
composés implémentent les opérations définies par cette interface en
terme de délégation vers ses enfants (qu'ils soient simples ou composés !-)

Dans un logiciel de dessin vectoriel, par exemple (et tout à fait au
hasard...), les 'objets simples' sont les primitives (lignes, texte,
courbe, ...), et tout le reste est 'composé' à partir des primitives
(par exemple, un rectangle est composé de 4 lignes, une boite avec titre
est composée de deux rectangles et d'un texte, etc...)


En bref, on a

+----------------+
| <<interface>> |
| Composant |
+----------------+
| +op1() | *
| +op2() | <-------------------------+
+----------------+ childrens |
^ |
| |
+-----------------+-------------+ |
| | |
+--------------+ +-------------------------------+ |
| Simple | | Composite |<>--+
+--------------+ +-------------------------------+
| +op1() | | +op1() : |
| +op2() | | for child in self.childrens:|
+--------------+ | child.op1() |
| (idem pour op2()) |
+-------------------------------+




Evidemment, Composite doit avoir quelques opérations supplémentaires
pour ajouter/enlever des enfants...

Dans ton cas, les opérations seraient quelque chose comme:
- draw()
- move_to()
- move_by()

etc...

Après, tu te retrouve avec deux cas de figure:
- les objets composés 'statiques ' (contruits en dur dans ton appli, ie
rectangles etc)
- les objets composés 'dynamiques': par exemple quand un utilisateur
sélectionne un groupe d'objets pour les déplacer.

Pour le second cas, il te suffit d'avoir une classe composée
'Selection', que tu crée - et détruuit - à la demande.


Sérieusement, achète toi le GoF. Non seulement pour avoir les patterns
sous le coude - et pour ce que tu es en train de faire, je pense qu'il y
en a pas mal d'autres qui te serviront -, mais aussi parce que c'est un
des meilleurs ouvrages existant sur la conception objet.


--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in ''.split('@')])"

Avatar
Bruno Desthuilliers
Tu connais le pattern Composite
non justement et je n'ai rien trouvé de clair sur le net pour m'éclairer sur ça.


Mmm... Il y a pourtant quelques ressources sur le sujet.

tu peux m'expliquer ou me donner des liens vers des exemples simples.


Un conseil : investit dans le GoF. C'est un des rares bouquins
d'informatique qui vaillent le coup.

Extrait dudit:

"""
Le modèle Composite compose des objets en des structures arborescentes
pour représenter des hiérarchies composants/composés. Il permet au
[code] client de traiter de la même et unique façon les objets
individuels et les combinaisons de ceux-ci.
"""

(je zappe l'exemple qui porte sur... les "applications graphiques telles
que éditeurs de dessins et systèmes de représentation schématiques" !-)

Le pattern se base donc sur la notion d'objets 'composants' - les
'primitives' de ton application, par exemple les formes de base - et
d'objets 'composés' - qui sont en fait des conteneurs d'objets
'composants'. Le principe est de manipuler - donc de représenter - de
façon uniforme les primitives et les conteneurs. Pour cela, on définit
pour cela une interface commune Composant qui précise les opérations
communes, et des classes "primitive" (les formes de base) et des classes
"conteneur" (les formes composées à partir de primitives - ou d'autres
composées...). Ces dernières définissent les opérations communes en
terme de délégation à leur composants.


Un schéma rapide :

+--------------+ +--------------+ *
| ClasseClient |--------> | <<abstract>> |<------------
+--------------+ | Composant | |
+--------------+ |
| op_one() | |
| op_two() | |
+--------------+ |
^ |
| |
--------------------- |
| | |
+-----------+ +-----------+ |
| Primitive | | Composite |<>---
+-----------+ +-----------+ childrens
| op_one() | | op_one() |
| op_two() | | op_two() |
+-----------+ +-----------+


class Composite(object):
def op_one(self, ...):
for child in self.childrens():
child.op_one(...)

class Primitive(object):
def op_one(self, ...)
really_do_something_here()


Voila pour le principe. Pour ce qui est de l'implémentation en Python,
la classe abstraite Composant n'a de sens que s'il y a factorisation
et/ou implémentation par défaut - l'essentiel est que toutes les classes
Primitives et Composites implémentent la même interface.

Dans ton cas, Rectangle et Texte semblent deux bon candidats pour des
classes "Primitives", et RectangleAvecTexte un composite. Une opération
commune est clairement la méthode draw(), avec ces implémentations:

class Rectangle(object):
def draw(self, canvas)
canvas.create_rectangle(self.x1,
self.y1 ,
self.x2,
self.y2,
fill=self.color,
width=self.width)

class Texte(object):
def draw(self, canvas):
canvas.create_text(self.x, self.y, self.text)

class AbstractComposite(object):
def draw(self, canvas):
for child in self.childrens:
child.draw(canvas)

class RectangleAvecTexte(AbstractComposite):
def __init__(self, rect, text):
self.childrens = [rect, text]


Ceci répond à ta seconde question. En ce qui concerne la première, il
suffit (... façon de parler...) d'avoir un Composite représentant par
exemple une sélection multiple :

class MultipleSelection(composite):
def __init__(self, *childrens):
self.childrens = list(childrens)

Quand nécessaire, tu crée une instance de cette classe avec en paramètre
les objets qui vont bien, et voilou... Bon, d'accord, ça ne répond que
partiellement à ta première question, et vu que je n'ai jamais utilisé
Tkinter, je laisse le relais à quelqu'un de plus averti sur ce point
(ie: comment récupérer les objets qui t'intéressent. Ceci étant, je
pense que si j'étais toi, je regarderais de plus près les méthodes
find_enclosed() et find_overlapped() de l'object Canvas.

Dernier point : les outils graphiques ayant été un des premiers terrains
conquis par l'approche objet (pour pas mal de raisons logiques et
historiques), pas mal des patterns du GoF portent sur ce type
d'application (Commande, Memento, Decorateur, Proxy etc). Je te
recommande *vraiment* l'investissement.

HTH