60

Kevin Kofler (./59) :
JackosKing (./57) :
Si tu regardes le contrat de setWidth: height constant.
Donc il faut interdire d'appeler setWidth sur un carré, par exemple:


Non.

61

(puisque ça "garantit moins à l'utilisateur", puisque celui-ci ne peut plus utiliser pleinement le carré comme étant un rectangle)
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

62

63

./60, ./61: Si la classe est COW, il n'est pas censé utiliser un Square* et le mettre dans un Rectangle*, il est censé utiliser un Square et le mettre dans un Rectangle et du coup il pourra utiliser setWidth. Si une fonction manipule un Rectangle*, elle n'a pas intérêt à casser les invariantes nécessitées par la fonction appelante, et cet héritage est un moyen efficace d'empêcher ça!

Il y a 2 cas:
* soit le possesseur de l'objet Square ne s'attend pas à ce que la fonction appelée détruise la propriété de l'objet d'être un carré, alors l'erreur est dans la fonction appelée ou dans sa documentation (qui ne spécifie pas cette partie de son contrat),
* soit le possesseur de l'objet le sait, alors l'erreur est là, il ne faut pas appeler cette fonction sur un Square*.
Dans les 2 cas, il y a une erreur quelque part.

Sans cet héritage, tu as besoin d'assertions assert(rect.height() == rect.width()); partout pour vérifier ton invariante.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

64

en java quand on veut faire des concaténations intensives, on prend un stringbuffer, et hop. Les performances sont pas si horribles, les opérations à effectuer n'étant pas vraiment compliquées...

Martial > c'est sur que troller c'est plus facile hein?

65

KK> je n'ai pas bien saisi ce que tu as voulu expliquer.
Tu as cependant relevé une chose importante du design by contract, c'est la notion d'invariant.
L'invariant est une condition qui doit toujours être vraie en entrée et sortie des méthodes de la classe. Cet invariant est bien entendu propagé par héritage (ce que confirme d'ailleurs Liskov). Il en advient alors l'évidence qu'un rectangle ne peut dériver d'un carré (pas trop dur lol).
Pour le sens inverse: le carré qui dérive d'un rectangle le problème vient de ton interface et ses contrats. Si tu veux respecter liskov, tu ne peux pas avoir un setW setH. Il en advient alors 2 solutions propres:
> Ne pas définir le setW et setH, et passer les dimensions en paramètre du constructeur. (chiant dans 90% des cas)
> Avoir une classe commune et dériver carré et rectangle de cette classe commune (AbstractRectangle) par exemple. On repousse alors le problème a la construction qui peut être résolu par une FACTORY.

Enfin ces deux solutions sont utilisées dans le cas où l'on souhaite utiliser la substitution. Dans le cas contraire il est possible d'agréger.

Un classe dérivée d'une classe mère doit toujours pouvoir passer le test unitaire de la classe mère.
Si l'on prend:

testSetterAndGetter(){
 .setW(5);
 .setH(7);
 TEST_EQ_ASSERT(.getW() == 5 && .getH() ==7) -> Test failed pour un carré
}

testArea(){
 .setW(5);
 .setH(7);
 TEST_EQ_ASSERT(.computeArea() == 5*7) -> Test failed pour un carré
}


Attention, il ne faut pas avoir l'envie de modifier le test unitaire pour le faire passer (en utilisant les getters pour le calcul d'aire etc.)!

66

JackosKing (./66) :
Un classe dérivée d'une classe mère doit toujours pouvoir passer le test unitaire de la classe mère.


ah c'est ça le concept important qui base ta théorie!
C'est une contraite assez forte je trouve, et je n'aurais pas pensé à la respecter naturellement.

hum... ça limite pas mal les possibilités par contre hum

67

Non, c'est normalement forcément le cas si tu respectes le "est un" et le principe de substitution de Liskov.
Si c'est un "est un", comment peut il ne pas passer le test de la classe mère ??

68

Ben parce qu'un carré est un rectangle.
Autrement dit il faut faire attention à notre formulation, la notion de "est un" n'étant pas très formelle.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

69

C'est pour cela qu'on ne dérive pas forcément lorsque l'on peut dire "est un".
C'est dure a faire passer comme idée, mais c'est pourtant très important!

70

je vois, en effet.

On apprend plutot la spécialisation, et la notion intuitive du "est un"

71

Désolé, mais pour moi, la relation "est un" est clairement définie, une classe A "est un" B si l'ensemble des objets de type A (dans la réalité) est un sous-ensemble de l'ensemble des objets de type B (ce qui est bien le cas pour A=carré et B=rectangle), et ça se modèle par un héritage.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

72

Bon et bien je te propose une petite lecture que j'ai trouvée sur le net:
http://www.objectmentor.com/resources/articles/lsp.pdf

Je rappelle qu'on apprend pas la POO avec un livre de C++ ou de Java, mais un livre de POO!
C'est pour cela que quand j'entends momotte dire que c'est une évidence, je pense qu'il y a beaucoup de détails qui sont incompris...

73

Mais ce que propose de faire, c'est de ne pas faire des setHeight et setWidth identiques pour un carré comme dans leur exemple, mais de les interdire (throw "You're about to violate the invariant of a square!") et d'introduire un setLength pour le carré. Et de plus introduire un copy-on-write (certes abusif pour un objet de 2 flottants, mais ce n'est qu'un exemple!) qui permet de faire "redevenir un rectangle" l'objet exactement quand on est en train de casser l'invariant sur une shallow copy.

Donc je ne respecte pas le principe de Liskov, mais AMHA c'est quand-même une solution valide au problème. Le monde réel ne suit pas vos principes théoriques!
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

74

Si si justement ce sont des principes pour le monde réel!!
Ce que tu proposes, c'est de la bidouille et cela ne donne pas du code réutilisable et propre.

Les bouquins de poo permettent justement de mieux programmer, et dire que c'est réservé aux livres est vraiment ridicule, c'est même un refus de progresser...

75

EDIT: hum... c'est gros.. desole triso il y a un TL;DR un peu plus bas si t'as la flemme grin

JackosKing> oh mais j'ai pas dit que c'etait forcement inutile hein... et si tu prends le temps de lire ces bouquins, tu tombera forcement sur des trucs interessants... je suis d'accord. (enfin, sauf si le bouquin est merdique, etc... triso)
("Je rappelle qu'on apprend pas la POO avec un livre de C++ ou de Java, mais un livre de POO! " --> heu, deja, on apprend pas forcement le C++ avec un "livre" de C++ non plus hein... trinon enfin si, a l'universite peut etre...)

et d'apres ce que j'ai pu observer, il y a plusieurs categories de developpeurs...
ceux qui rament et qui essayent d'apprendre par coeur des regles de code, des algos, des "methodes" de programmation, en esperant que tout d'un coup ils vont bien coder, mais qui au final n'arrivent a rien, parcequ'en pratique, juste apprendre betement, ca ne sert a rien des que tu t'attaques a du vrai dev et que tu sors du tout-theorique, ou des exercices qu'on te donne a l'ecole.
le fait est qu'ils restent mediocres d'un point de vue technique, et ne valent strictement rien des qu'il s'agit d'architecturer/d'abstraire/d'optimiser/de generaliser/etc.etc. du code... en gros tout ce qui n'est pas mecanique et qui ne peut pas etre fait ou resolu en appliquant les recettes de cuisine qu'on leur a appris.
je sais pas si c'est une limitation de leur esprit logique ou autre chose...
(je dis ca sans aucune mechancete, ou sans les prendre de haut hein, la plupart des gens que j'ai rencontre qui correspondent plus ou moins a ce cas la sont souvent tres bons dans d'autres domaines (ou meme juste quand on considere la chose d'un point de vue different), ca n'est pas une question d'etre plus ou moins intelligent, l'intelligence a plein de declinaisons differentes, mais juste une question de comment fonctionne le mode de pensee de la personne.)

ensuite d'un autre cote t'en as pour qui le genre d'architectures expliquees dans ces bouquins/articles de POO vient naturellement, qui font tout ca d'instinct, et avec qui tu n'as meme pas besoin de connaitre tous ces _termes_ specifiques quand tu discutes, vu que lorsque tu parle de code, d'algos, ou d'architecture de programmes, tu n'abordes quasiment jamais (enfin ca ne m'est jamais arrive avec eux en tout cas), des "details" comme les designs patterns (bon c'est pas des details, mais comme dit au dessus: ca vient naturellement)...
par exemple j'ai vu certains stagiaires (ok, tres peu, mais quand meme), avec qui tu n'as absolument pas besoin de te prendre la tete sur ca. tu leur dis quoi faire, et ils architecturent tout d'instinct... (pour apres eventuellement se rendre compte, si ils parlent a un adepte de la theorie de la POO, qu'en fait ils respectent tel ou tel principe enonce par tel ou tel bonhomme, qu'ils utilisent tel ou tel design pattern, etc... mais au final, ca va pas leur changer leur vie, si le type avait pas ete la pour enoncer son truc, ils auraient quand meme pondu le meme code.)

(d'ailleurs, chose marrante, personnellement, je trouve que ces regles enoncees sont pour la plupart totalement imbitables (oue, comme mes posts, desole.. :/ je fais des efforts pourtant triso), et il faut que je les lise en faisant vraiment attention pour etre sur de bien capter (sauf quand il y a un exemple en code ou un schema explicatif "visuel" a cote), alors que ce qu'elles enoncent parait d'une evidence affligeante, c'est probablement la aussi une limitation de l'esprit, moi par exemple, bah je suis hermetique aux theoremes qui ont ete enonces en essayant de les rendre les plus clair/generaux/justes possibles... c'est juste... hm.. "sick")

tiens, exemple, toujours dans ton article:
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

--> wtf... sick


TL;DR: certains font tout ca d'instinct, tout comme certaines personnes ont une facon de penser propice aux representations mentales de problemes en 3 dimensions, ou a la creation musicale, d'autres en ont une propice entre autres a l'architecture de POO, etc... (ca peut paraitre ridicule dit comme ca, mais... non... vraiment..)

evidemment apres il y a les subtilites du langage, mais comme tu dis, c'est autre chose... difference entre un bouquin de C++ et un bouquin de POO
Si si justement ce sont des principes pour le monde réel!! Ce que tu proposes, c'est de la bidouille et cela ne donne pas du code réutilisable et propre.

oue, mais je rejoins un peu KK la dessus, malheureusement, le "monde reel", les prods concretes, (de ce que j'ai pu en voir en tout cas), c'est de la bidouille, et c'est crade...
ceux qui ont le luxe de faire des trucs bien propres, c'est ceux qui n'ont pas de vraies contraintes de temps ou d'argent... (oue, c'est un luxe de ne pas avoir de contraintes de merde qui t'empechent de faire ce que t'aimerais)
genre par exemple, des theoriciens, des chercheurs, ou bien ceux qui n'ont pas de deadlines "dures", ou bien des geeks de l'open source qui aiment passer toutes leurs nuits a se branler sur une template C++ de 10 lignes "sooo clever"© pendant 2 semaines... bref..

(ok c'est carricatural, et j'ai pas enormement d'experience non plus, si on relativise (peut etre moins que toi, mais deja on n'a probablement pas eu la meme...), mais de ce que j'ai pu voir, les contraintes de production font que meme malgre la meilleure volonte du monde, tu sera a un moment ou a un autre face a un choix dans le genre: passer une semaine a refactorer un module parceque ton cahier des charges a change de facon legere mais sournoise, ou bien une apres-midi a hacker les nouvelles fonctionnalites dans ce qui existe deja.
avec une deadline le lendemain, c'est vite vu...
(tu peux toujours dire "c'est parceque c'etait mal concu au debut", mais, non.. ca peut tout a fait arriver meme si c'etait bien concu pour coller au premier cahier des charges)
(la encore j'exaggere avec cet exemple, mais c'est pour que ca soit explicite grin (enfin, j'exagere... c'est vite dit... des fois y a meme pas de cahier des charges... triso)))
avatar
HURRRR !

76

squalyl (./64) :
en java quand on veut faire des concaténations intensives, on prend un stringbuffer, et hop. Les performances sont pas si horribles, les opérations à effectuer n'étant pas vraiment compliquées...

attention En général, on doit utiliser un StringBuilder, pas un StringBuffer (StringBuffer est synchronisé)

D'ailleurs, la différence entre Vector et ArrayList est la même (Vector est synchronisé, pas ArrayList)

77

sBibi > Il y a aussi un autre type de programmeur dont tu n'as pas parlé, qui se plonge dans son code directement sans se demander s'il va utiliser tel ou tel design pattern (car il ne sait pas ce que c'est) et qui va te pondre un code plutôt impossible à maintenir et à débugger. S'intéresser aux méthodes de développement objet (comme les design pattern) permet à ces gens là de mieux organiser leur code.
Enfin, un autre avantage des design pattern est que comme on a affaire à des pattern, on peut facilement trouver un moyen de générer notre code plutôt que de le réécrire à chaque fois.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

78

penpen > je sais, j'ai passé la jre au peigne fin.
Dans les vieilles version c'est un buffer, dans les nouvelles c'est un builder. OK pour la différence.

momotte > #totalcrayon#

79

Sasume> oui, aussi, mais la ce dont tu parles c'est une difference a un autre niveau, je vois plus ca comme une difference de methode / d'organisation / de flemme, etc... non?

tu peux tres bien le retrouver dans les deux types dont je parlais.
meme quelqu'un qui a l'"instinct" de la POO, si il a la flemme de reflechir, et se lance dans son code a l'aveuglette sans avoir la moindre idee de la ou il va aller, va tres probablement faire de la merde, oui... (sans meme parler de l'autre type grin)

EDIT: (sans forcement se poser la question "quel design pattern vais-je utiliser", par definition, si il arrive a faire ca d'instinct, il n'a pas besoin de selectionner ou de connaitre un design pattern particulier, il va intuitivement trouver qqch d'adapte au probleme pour peu qu'il se donne la peine de reflechir avant de se lancer tete baissee dans son code, ca, personne n'y echappe (sauf peut etre quelques rares gourous, mais bon meme la j'ai quelques doutes quand meme grin))
avatar
HURRRR !

80

momotte (./75) :
tiens, exemple, toujours dans ton article:
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

--> wtf... sick

Sur ce point, je dois défendre l'article, pour moi ce qu'il veut dire est tout à fait clair.

En revanche, pour en revenir à l'exemple des carrés et des rectangles: si j'ai bien compris, la solution proposée par l'auteur de l'article et aussi par JackosKing est d'avoir une classe abstraite AbstractRectangle qui définit des fonctions getHeight, getWidth, getArea, ..., mais pas de setters, puis d'avoir une classe Rectangle et une classe Square qui dérivent toutes les 2 de AbstractRectangle et proposent les bons setters. Cette méthode est valide et va fonctionner correctement, mais il y a un grand problème: si Rectangle a été développé sans penser à l'ajout successif d'une classe "carré" (comme le présuppose justement l'article à plusieurs endroits), alors il n'y aura certainement pas la bonne classe AbstractRectangle et donc on se retrouve à devoir changer toutes les utilisations de const Rectangle * en const AbstractRectangle * (idem pour les références), il faut donc retoucher tout le code (même si on utilise un remplacement global automatique, ça implique quand-même de tout recompiler), c'est la galère.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

81

Tiens, je suis d'accord avec momotte ^^ (et avec KK... la solution de Jackos demande qu'on ait absolument pensé à tout avant de développer... or je n'ai jamais réussi à être dans un tel cas, il y a systématiquement un moment où quelque chose a été oublié - que ça soit la faute à l'analyse côté informatique ou aux informations données par le client).
avatar

82

D'où l'intérêt, à mon avis, de s'intéresser aux outils formels de modélisation et conception (tels que les design pattern), qui permettent d'anticiper d'avoir du recul sur une modélisation, évitant ainsi les erreurs qui induiraient une refonte profonde du code au moindre changement du cahier des charges.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

83

avec des trucs comme ça, on a demandé à ma copine de faire une architecture MVC sur une application du type

quantite <textbox>
devise source <dropdown euro, dollar, etc>
devise cible <la meme chose>
label <resultat>
button <convetir>

sick belle perte de temps, ils auraient mieux fait de faire un projet conséquent avec une VRAIE utilité du mvc, pas sur une connerie qui rend complexe un truc ultra simple triso

84

Quand on apprend, on doit souvent commencer par faire des trucs très simples avec des outils très compliqués, hein ^^
Généralement, on commence par faire une calculette, mais ça correspond peu ou prou à ça.
avatar

85

86

momotte (./75) :
(enfin, j'exagere... c'est vite dit... des fois y a meme pas de cahier des charges... triso.gif )
2 ans et demi que je bosse, j'ai eu l'occasion de travailler en technique sur différents projets, j'ai jamais vu passer l'ombre d'une spec. Alors un cahier des charges...
(évidemment je compte pas les missions d'étude/audit, où là le cahier des charges et les livrables sont clairement définis... et sont des documents Mot et PuissancePoint.)

87

(Ca fait plaisir de voir que c'est pas spécifique à chez nous ^^)

Ah et je ne résiste pas au plaisir de vous montrer ce à quoi ressemble un cahier des charges quand on en a un (depuis le temps que je le promettais à momotte ^^)... noter qu'on n'en connaît pas plus à la problématique que vous, hein, et qu'il n'y a pas d'autre page ^^
mirari/8w41
avatar

88

lolpaf .... et bon courage cheeky
avatar
<<< Kernel Extremis©®™ >>> et Inventeur de la différence administratif/judiciaire ! (©Yoshi Noir)

<Vertyos> un poil plus mais elle suce bien quand même la mienne ^^
<Sabrina`> tinkiete flan c juste qu'ils sont jaloux que je te trouve aussi appétissant

89

J'aime bien la fin de la parenthèse sur l'email grin "comme prévu"
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

90