[Mainly C#]Mon apprentissage de l'objet (et du C#)

Donc comme écrit quelque part dans cette section, j’apprends le C# avec en bonus l’apprentissage de l’objet. Et j’aimerais vous faire part de mes remarques sur le sujet pour pouvoir continuer a apprendre sur le sujet, l’auto-formation c’est bien mais il faut être capable d’analyser tout seul une mauvaise utilisation de l’outil et c’est pas toujours facile.

J’ai appris qu’un bon objet était un objet « fermé ». Comprendre que les variables de l’objet sont private (ou protected) et qu’il faut utiliser des méthodes pour accéder aux données.
Exemple:

public class element:ICloneable { protected String title; protected String text; protected int x; protected int y; protected int fontsize; public string get_title() { return title; } public string get_text() { return text; } public int get_x() { return x; } public int get_y() { return y; } }
good

public class positions { public int Offset_X; public int Offset_Y; public int Initial_Off_X; public int Initial_Off_Y; public int Pict_Off_X; public int Pict_Off_Y; public int Pict_Size_X; public int Pict_Size_Y; public int Removed_stickers; }
bad
NB: j’ai pas mis toutes les methodes.

Bon fondamentalement, je comprends pas la nécessité du private/protected.

Si la class element est en protected, c’est que les variables ne sont pas utilisées hors de la classe ou des héritages - les méthodes GET ont été utilisé a la création de la classe mais ne servent plus actuellement. En effet, les données sont initialisées via le créateur « public element(XmlNode el) » et les données sont utilisées dans « public void draw_element(Graphics display, FontFamily standard, positions offset) » ou je dessine les données sur un objet Graphics.
Dans ce cas la, le protected est tout a fait cohérent car l’appelant de l’objet n’a pas besoin de savoir ce qu’il y a dedans.

Pour le deuxième cas « bad », la classe sert plus de structure de données (comme en C). Les données stockées servent directement dans le programme appelant, peuvent être modifié, etc. J’ai beau retourner le problème dans tous les sens, je trouve que la mise en place de méthode set_Offset_X et get_Offset_X (and so on) est une perte de temps improbable. Pour le coup, je préfère a la limite utiliser les propriétés avec get/set plutôt que de faire des méthodes pour chaque variable (ca revient a faire des méthodes, mais l’utilisation finale est similaire a celle d’une structure). Mais encore une fois, si c’est pour faire une série de propriétés « get { return prenom; }/set {prenom=value;} », c’est se donner du taf pour pas grand chose. Sauf si dans l’étude, on a vu que ca pourrait être bien au cas ou un traitement de la données était nécessaire au moment du set/get (ce qui reste discutable, je préfère largement faire ce traitement sur le constructeur et avoir la « vraie » valeur stockée)

Votre avis? Plus précisément est ce que les programmeurs objets de la zone font leur classe avec TOUT en private ou certains objets peuvent avoir la majeur partie en public?

NB: je sais, j’ai pas utilise les recommandation C# pour le nommage, je le ferais la prochaine fois :smiley:
NB2: Les variables en private sont quasi obligatoire quand on utilise une interface - enfin je crois. Maintenant l’intérêt d’une interface dans un petit projet ou il n’y a qu’une personne dessus reste hautement discutable - c’est plus proche de la perte de temps qu’autre chose a mon sens. Je vois plus son utilisation dans des projets plus gros, ou il y a des grosses specs bien détaillées, celles ci précisant pratiquement les interfaces qu’il faudra créer/utiliser.
NB3: Ah oui, un truc drôle: il n’existe pas en C# d’argument optionnel, on utilise plutôt la surcharge (genre public void toto(int gnia) et public void toto(int gnia, string truc)). Ca fait deux méthodes qui font pratiquement la même chose, ce qui veut dire qu’il faut refactoriser le code commun dans une 3eme méthode. Je trouve pas ca super pratique, si quelqu’un a une solution « state of the art », ca m’intéresse.

LoneWolf
Learning Object Oriented Programming

Alors personnelement, j’utilise les snippets quand je code, donc pour faire tout les accesseurs et setter donc j’ai besoin dans une classe j’utilise la combinaison

‘prop’ + la touche de tabulation.

Qui va te générer un

cette snippet etant là pour faire gagner du temps à la construction des classes, je ne crée des variables privées ou protected que si elles me sont vraiments necessaires et n’ont pas besoin d’être accessible.

Primo, les variables internes à la classe ne doivent pas être protected, uniquement private, sauf cas exceptionnel.

Jamais rien de public SI la classe est destinée à être exposée en dehors de la librairie.

Pour les classes internes à la librairie ou carrément les classes privées, alors osef, tu fais ce que tu veux.

Tu n’as pas l’air de connaître les propriétés ? Ou bien leur omission est volontaire ?

[code]public class Element : ICloneable
{
private readonly string title;
private readonly string text;
private readonly int x;
private readonly int y;
private readonly int fontSize;

public Element(XmlNode source)
{
	// Initialisation variables privées
	// this.x = int.Parse(source.Elements["x"].Value);
}

protected string Title
{
	get { return this.title; }
}

/// etc...

}[/code]

Ton problème a plus l’impression d’être lié à l’aspect immuable de tes classes.

Ca pique au yeux :smiley:

Une version propre de tes 2 classes la, ca donnerait a peu pres :

[code] public class Element : ICloneable
{

	private string title;
	
	protected Title
	{
		get { return title };
	}
	
	// etc...

}[/code]
good

[code] public class Positions
{
public Size Offset { get; set };
public Size Initial_Off { get; set; };
// etc…

	public int Removed_stickers;
}[/code]

Alors pour répondre à la question principale qui est pourquoi les variable en private dans les objets, c’est une question orienté objet, c’est comme ça dans tous les langages OO, que ce soit C#, Java, Eiffel, Ruby et j’en passe.

Les raisons en sont multiples. Je dirais que la première raison et une des plus importantes est le concept d’encapsulation. L’idées est qu’une classe est quelque chose de fermé, qui va être utilisé par d’autres classes sans que celles-ci soient intéressées par leur fonctionnement. C’est un peu la même idée que dans la vraie vie, quand tu utilises une lampe par exemple, tout ce qui t’intéresse c’est d’appuyer sur un bouton et qu’elle s’allume, tu t’en fiches qu’elle contient une ampoule, qui elle-même contient un filament, etc. L’idée ici est identique, on veut cacher l’implémentation des choses et ne laisser visible que ce qui est réellement important.

Je vois que tu viens du monde du C, et bien tu sais qu’on évite en C de créer des variables globales à un programme qui seraient modifiées par des méthodes appelées, afin d’éviter des effets de bord. Et bien là c’est identique, mettre toutes les variables en publique risqueraient de créer des effets de bord qui sont toujours très emmerdant à débugger.

Une autre raison aux getter/setter, ou leur pendant C#, les properties, c’est que cela permet de faire des vérifications au moment du set. Imaginons que tu aies une classe Person et que Person ait besoin de stocker l’âge. Si tu utilises une variable publique, un utilisateur de ta classe pourrait très facilement faire maPerson.Age = -30, ce qui risquerait de faire planter ton programme. Avec une property tu as la possibilité de vérifier les inputs et donc vérifier par exemple que l’âge soit plus grand que 0 et moins que 200 par exemple et envoyer une Exception si ce n’est pas le cas. (bon c’est un mauvais exemple l’âge hein, on mettrait la date de naissance :D).

Et faut eviter les exceptions dans les accesseurs il me semble non ? J’ai souvenirs que FxCop m’avait engueulé pour ca :smiley:

Qu’est-ce que tu entends par accesseur? Tu veux dire dans le get d’une Property? En effet je ne vois pas vraiment de cas où ça aurait un sens. Par contre dans le set c’est très courant et je dirais même conseillé.

[quote=« Styx31, post:3, topic: 50983 »]Primo, les variables internes à la classe ne doivent pas être protected, uniquement private, sauf cas exceptionnel.

Jamais rien de public SI la classe est destinée à être exposée en dehors de la librairie.[/quote]
C’est ce que je lis partout, mais c’est difficile d’obtenir le pourquoi.
Gimly me propose un pourquoi, ie « une classe doit être une boite noire », mais j’avoue bien que j’ai jamais aime les boites noires, j’aime bien savoir comment ca marche dedans.

Je connais mais je vois pas l’intérêt de perdre du temps a reprendre la 10aine de variables contenue dans la classe positions et de faire, pour chaque variable, un get/set alors qu’elle est accessible directement par la variable elle même. C’est juste un problème d’avoir une raison.
Gimly fourni un élément de réponse, même si j’arrive pas a voir sur quoi cette affirmation repose.

La par contre, j’ai pas compris.

De quoi? Mon nommage ou le lien que j’ai mis qui explique les bonnes méthodes de nommage?

Ouais enfin moi j’ai du mal a comprendre ca. Faut voir que position, avant, c’etait un int offsets=new int[8]; pour stocker toutes les données. Bah ouais, a l’ancienne hein. J’ai trouve ca moche et j’ai fait un objet, mais je n’arrivais pas a voir une raison (technique) qui pourrait nécessiter de mettre les var en private.

clair, les variables globales c’est le MAL et pourtant, en C#, on fait des variables globales (ou presque) : Je peux pas passer de variable a la méthode qui gère le click sur un bouton, donc fondamentalement, j’ai une variable globale (sous entendu, a la classe, certes) qui pourra être utiliser. Mais les effets de bords sont toujours présent.
De plus, malgre ce que tu explique, je vois pas la diff entre:

public int toto;

et

private int toto; public int Toto { get; set; }
En considérant qu’on ne fait aucun contrôle dans la propriété, bah c’est la même chose en fait.

Ouais. Je suis pas dans ce cas la ici (données rentrées par l’utilisateur) mais puisque tu en parles:
Choix 1: Le test de validité est fait lors de la saisie
Choix 2: Le test de validité est fait lors de l’affectation a la variable dans l’objet (set)
Instinctivement, j’ai tendance a croire que le Choix 1 me permet d’être moins sujet a un buffer overflow ou un effet de bord, car on gère ca au plus près de la récupération.
Pourtant, le choix 2 semble être plus logique « objet-ivement parlant », avec l’envoi d’une exception quand c’est pas bon (ce qui signifie un try/catch lors de l’affectation), mais bon, y a un piège nan?

LoneWolf
Déjà merci les gens :smiley:

J’ai l’impression que tu pars pas mal du principe que tu es le seul à utiliser l’objet. Alors que l’idée quand même c’est justement de d’encapsuler un certain nombre de propriété et de fonction dans un objet, et avoir un interface clair et simple, masquant au maximum la complexité de l’objet pour qu’il puisse être réutilisé facilement (par toi dans 6 mois dans un autre projet ou par d’autre).
Genre dans ton dernier exemple ou tu proposes de faire des test de validité lors de la saisie, c’est juste super pas pratique si tu veux utiliser ton objet ailleurs puisque ce test devra être refait à chaque fois que tu utilises l’objet dans différents projets.

En effet, c’est dans les get, pas dans les set : http://msdn.microsoft.com/en-us/library/bb…8VS.100%29.aspx+

Et non, lonewolf,

private int toto;
public int Toto{ get; set; }

c’est loin d’etre la meme chose que

public int Toto;

Dans le premier cas, toto aura jamais la valeur que tu definis sur Toto. Ensuite, ce cas te permet d’avoir la flexibilité necessaire si un jour tu veux checker ta variable, ou renvoyer un truc calculé. (google autoproperty)
Ensuite, tu peux aussi tres bien faire public int Toto { protected get; private set; }, qui te permettrais d’autoriser la lecture dans les sous classes, mais pas l’ecriture hors de la classe elle meme. Et oui, c’est une histoire d’encapsulation. Va falloir te coltiner des articles sur la POO si vraiment tu veux les raisons :smiley:

Sans vouloir paraître méchant, est-ce que tu as acheté un livre sur l’orienté objet? Ce sont des concepts quand même relativement compliqués à appréhender et qui paraissent peu naturels au début, donc un peu de théorie ne fait jamais de mal.

[quote=“LoneWolf, post:9, topic: 50983”]C’est ce que je lis partout, mais c’est difficile d’obtenir le pourquoi.
Gimly me propose un pourquoi, ie “une classe doit être une boite noire”, mais j’avoue bien que j’ai jamais aime les boites noires, j’aime bien savoir comment ca marche dedans.[/quote]
Ben oui mais le concept de “boîte noir” c’est la pierre angulaire des langages OO, le but est de maximiser la réutilisabilité du code et de pouvoir utiliser des librairies sans avoir à se soucier du comment elles ont été faites et seulement du comment elles fonctionnent. Certains devs “old school” critiquent cette approche en disant que l’on ne crée des programmes plus qu’en montant ensemble des pièces de légo, mais franchement ça permet surtout d’éviter de réinventer la roue 1000x et diminue les temps de développement.

[quote=“LoneWolf, post:9, topic: 50983”]clair, les variables globales c’est le MAL et pourtant, en C#, on fait des variables globales (ou presque) : Je peux pas passer de variable a la méthode qui gère le click sur un bouton, donc fondamentalement, j’ai une variable globale (sous entendu, a la classe, certes) qui pourra être utiliser. Mais les effets de bords sont toujours présent.
De plus, malgre ce que tu explique, je vois pas la diff entre:[/quote]
Non, normalement même en interne de la classe il est bon d’éviter de modifier les valeurs des variables de classe (privées) et donc toujours passer par les properties. A nouveau, ça permet de faire les potentielles validations. De plus, si tu mets ta variable public, non seulement tu risques d’avoir des effets de bord à l’intérieur de ta classe, mais aussi depuis les classes appelantes, et là ça devient encore plus le bordel.

[quote=“LoneWolf, post:9, topic: 50983”]public int toto;
et

private int toto; public int Toto { get; set; }
En considérant qu’on ne fait aucun contrôle dans la propriété, bah c’est la même chose en fait.[/quote]
D’abord une remarque, si tu utilises la nouvelle (existe depuis .Net 3.5) syntaxe {get; set;} tu n’as pas besoin (et même ne doit pas) mettre de variable privée, c’est un raccourcis d’écriture qui va être remplacé par le compilo en

private int _toto; public int Toto { get { return _toto; } set {_toto = value;} }

Ensuite, tu as tout à fait raison, les deux choses sont identiques dans ce cas vu qu’il n’y a pas de validation. Par contre, imagine maintenant que tu es parti avec la solution 1) et que ta classe est utilisée par une 20 aine d’autres classes et que tout à coup tu as besoin d’ajouter une validation, et bien tu es dans la m… Tu vas devoir te taper l’entier des classes pour changer et utiliser une property. Et surtout, aucune erreur de compilo te dira si tu en as oublié une, donc tu risques de faire des erreurs.

[quote=“LoneWolf, post:9, topic: 50983”]Ouais. Je suis pas dans ce cas la ici (données rentrées par l’utilisateur) mais puisque tu en parles:
Choix 1: Le test de validité est fait lors de la saisie
Choix 2: Le test de validité est fait lors de l’affectation a la variable dans l’objet (set)
Instinctivement, j’ai tendance a croire que le Choix 1 me permet d’être moins sujet a un buffer overflow ou un effet de bord, car on gère ca au plus près de la récupération.
Pourtant, le choix 2 semble être plus logique “objet-ivement parlant”, avec l’envoi d’une exception quand c’est pas bon (ce qui signifie un try/catch lors de l’affectation), mais bon, y a un piège nan?[/quote]
Alors là attention. Il y a un autre concept très important en OO, c’est le separation of concerns, à savoir que normalement chaque partie d’un programme ne devrait s’occuper que d’une seule et unique chose. Donc, la partie UI et la partie logique d’une application devraient être séparés (avoir de la logique dans le codebehind d’une WinForms c’est le mal). Comme chaque partie du programme doivent être séparés, en général la validation se fait donc à plusieurs niveau. C’est à dire que tu vas d’abord faire de la validation au niveau des entrées utilisateurs, mais tu vas aussi en faire à des niveaux plus “bas” de ton application. Ca te permettra à l’avenir de garder le même noyau de l’application et d’avoir, par exemple, une interface graphique web.

Donc la bonne solution serait de faire la validation aux deux endroits.

[quote=« LoneWolf, post:9, topic: 50983 »]C’est ce que je lis partout, mais c’est difficile d’obtenir le pourquoi.
Gimly me propose un pourquoi, ie « une classe doit être une boite noire », mais j’avoue bien que j’ai jamais aime les boites noires, j’aime bien savoir comment ca marche dedans.[/quote]
Il faudra pourtant t’y habituer, en objet l’important c’est l’API, ce qui a derrière OSEF. Une implémentation peut très bien être remplacée par une nouvelle plus performante, du moment qu’elle respecte la même interface (cad le même contrat), ça ne posera aucun problème sur tes développements, et tu ne t’en rendera peut-être même pas compte.

Ton nommage ! Chaque language a ses propres règles de nommage et il est très important de les respecter afin de facilité la compréhension d’un code par les autres développeurs. Par exemple, en Java dès que l’on fait référence à MonMachin, je sais tout de suite que c’est une classe alors que si c’était écrit Mon_machin, je ne pourrais pas savoir si c’est une classe, une variable ou une propriété sans avoir le contexte. Pire si tu nomme une classe monMachin, je pourrais croire qu’il s’agit d’une propriété/variable. (dsl pour l’exemple en Java alors qu’on parle C#, c’était pour l’explication)

[quote]Ouais. Je suis pas dans ce cas la ici (données rentrées par l’utilisateur) mais puisque tu en parles:
Choix 1: Le test de validité est fait lors de la saisie
Choix 2: Le test de validité est fait lors de l’affectation a la variable dans l’objet (set)
Instinctivement, j’ai tendance a croire que le Choix 1 me permet d’être moins sujet a un buffer overflow ou un effet de bord, car on gère ca au plus près de la récupération.
Pourtant, le choix 2 semble être plus logique « objet-ivement parlant », avec l’envoi d’une exception quand c’est pas bon (ce qui signifie un try/catch lors de l’affectation), mais bon, y a un piège nan?[/quote]
La réponse est Choix 1 + 2, le choix 1 est évident, il faut faire des vérification en amont et prévenir l’utilisateur des erreurs. Mais si tu te limites au Choix 1, lorsque ton objet sera utilisé par un autre composant (batch, une seconde interface de type web, un accès par webservice), il faudra aussi vérifier que la modification de la variable ne rendra pas l’objet dans un état incohérent, donc tu refait une vérification.

Une des solutions est de gérer tout ça avec des exception, on tente de faire l’affectation sans vérification, si une exception est levée, on la récupère au niveau de l’interface pour afficher un joli message d’erreur. Ce n’est pas toujours évident à gérer en cas de client léger.

protected offre le même niveau d’encapsulation que public, à savoir aucun. Alors c’est certes restreint aux classes dérivées, mais le problème reste dans le fond le même. Si on change un membre public, tous les clients de la classe seront potentiellement affectés. Si on change un membre protected, ce sont toutes les classes qui auront été dérivées de cette classe qui seront potentiellement affectées. Dans les deux cas, on n’a aucun contrôle sur la quantité de code impactée. Je te laisse imaginer les dégâts auxquels on peut s’attendre si la classe fait partie d’une librairie…

En général, si une classe doit fournir un accès à une de ses données privées, il vaut donc mieux introduire un accessor protected correspondant. C’est exactement la même idée que les accessors publics, mais dans le cas des hiérarchies de classes.

Un software, c’est par nature complexe. Les classes, les fonctions, whatever, tous sont des concepts qui permettent de décomposer cette complexité afin que le programmeur puisse gérer la complexité inhérente à sa tâche. Rien n’empêche de s’intéresser à comment ça marche dedans (la curiosité, ça a du bon, et on peut apprendre énormément), mais ce qui est important, c’est que lorsqu’on utilise un concept on ne mette pas son nez dans l’implémentation. On s’en tient à l’interface qui est la garantie contractuelle avec le programmeur en face. Tant que le contrat ne change pas, il pourra améliorer son implémentation, ton code ne sera pas impacté.

De plus, si une fonction n’offre pas un niveau d’encapsulation suffisant et doit être traitée comme une white box pour être utilisée correctement, les clients vont se retrouver couplés à l’implémentation de la fonction qu’ils appellent. Si on se met à exploiter les détails d’implémentation, comment alors garantir que le code client fonctionnera toujours si l’implémentation de la fonction vient à changer? Comment ne pas oublier de mettre à jour tous les appelants lorsque l’implémentation de la fonction vient à changer? Un cauchemar.

Si il a le controle du code sur toute la solution, avec un peu de refactoring, c’est 3min :smiley: Mais c’est vrai que c’est mieux d’avoir prevu le coup.

La réutilisation du code est effectivement un argument de la POO, et j’ai encore du mal a le voir dans les faits. Les objets que j’ai fait n’ont pas pour vocation d’être réutiliser.
Ils sont la parce que je programme en C# et qu’il faut faire des objets. J’ai bien conscience que je prends le truc a l’envers mais j’ai jamais réussi a comprendre l’intérêt de la POO en théorie, donc je commence par la pratique pour voir.
Apres j’en ai pas parle mais c’est vrai que ca fait plus de 15 ans que je fais de la prog « classique » (C/ASM/PHP/Shell/Awk en gros) et que la POO change pas mal de choses, j’essaye malgre tout de m’adapter.

Ca n’a rien de mechant et j’ai pas de livre de POO, j’ai eu des cours et j’ai jamais compris (par manque de pratique a mon sens)
La je prends la pratique d’abord.

Pour moi ca, c’est l’utilisation d’une API. Donc un .so ou un .dll que tu utilises suivant des règles établies.
D’après ce que j’ai compris, quand on cree un objet, il faut avoir déjà réfléchi a ces règles d’utilisation avant et pendant la création de la classe. Et on utilise la classe comme une API. Bah oui mais perso, j’ai toujours considéré que l’API etait figé, alors qu’un objet va forcement évolué au cours du projet, et des règles établies pourrait remettre en question l’objet entier.
Ca rigidifie le développement de manière incroyable, ou alors j’ai rate un truc.

La par contre je suis perdu. Si la remarque d’ana-i est pertinante sur la flexibilite, si la propriete n’a pas de validation, c’est la meme chose! De plus, je vois pas du tout le concept d’effet de bord ici. La variable est public, on fait ce qu’on veut avec, et puis c’est tout.

[quote=« Gimly, post:12, topic: 50983 »]D’abord une remarque, si tu utilises la nouvelle (existe depuis .Net 3.5) syntaxe {get; set;} tu n’as pas besoin (et même ne doit pas) mettre de variable privée, c’est un raccourcis d’écriture qui va être remplacé par le compilo en

private int _toto; public int Toto { get { return _toto; } set {_toto = value;} }

Ensuite, tu as tout à fait raison, les deux choses sont identiques dans ce cas vu qu’il n’y a pas de validation. Par contre, imagine maintenant que tu es parti avec la solution 1) et que ta classe est utilisée par une 20 aine d’autres classes et que tout à coup tu as besoin d’ajouter une validation, et bien tu es dans la m… Tu vas devoir te taper l’entier des classes pour changer et utiliser une property. Et surtout, aucune erreur de compilo te dira si tu en as oublié une, donc tu risques de faire des erreurs.[/quote]
Ouais en fait je pense que c’est ca le problème: on parle pas de la même chose car c’est pas la même échelle. J’ai 3 classes et une 10aine de méthode a tout casser.
Et c’est pour ca que j’ai du mal a comprendre.
Les principes de la POO sont quasi obligatoire sur un projet d’envergure, car le temps utilise en amont fera gagner plein de temps au milieu et a la fin.
En revanche, sur un petit projet, l’intérêt est beaucoup plus limité, car cela va consommer pas mal de temps.

[quote=« Gimly, post:12, topic: 50983 »]Alors là attention. Il y a un autre concept très important en OO, c’est le separation of concerns, à savoir que normalement chaque partie d’un programme ne devrait s’occuper que d’une seule et unique chose. Donc, la partie UI et la partie logique d’une application devraient être séparés (avoir de la logique dans le codebehind d’une WinForms c’est le mal). Comme chaque partie du programme doivent être séparés, en général la validation se fait donc à plusieurs niveau. C’est à dire que tu vas d’abord faire de la validation au niveau des entrées utilisateurs, mais tu vas aussi en faire à des niveaux plus « bas » de ton application. Ca te permettra à l’avenir de garder le même noyau de l’application et d’avoir, par exemple, une interface graphique web.

Donc la bonne solution serait de faire la validation aux deux endroits.[/quote]
Ouais. Ca aussi il faut que je vois. J’ai encore du mal a transmettre les variables entre les differents blocs ceci dit.

On m’a jamais appris a nommer mes variables en C, a part la regle de base « il faut que ca parle! » donc pas de int a,b,c; :smiley:

[quote=« ZGoblin, post:13, topic: 50983 »]La réponse est Choix 1 + 2, le choix 1 est évident, il faut faire des vérification en amont et prévenir l’utilisateur des erreurs. Mais si tu te limites au Choix 1, lorsque ton objet sera utilisé par un autre composant (batch, une seconde interface de type web, un accès par webservice), il faudra aussi vérifier que la modification de la variable ne rendra pas l’objet dans un état incohérent, donc tu refait une vérification.

Une des solutions est de gérer tout ça avec des exception, on tente de faire l’affectation sans vérification, si une exception est levée, on la récupère au niveau de l’interface pour afficher un joli message d’erreur. Ce n’est pas toujours évident à gérer en cas de client léger.[/quote]
Les exceptions, meme si j’ai compris, sont encore un concept passablement flou ou j’ai du mal a voir s’il faut faire un try/catch de tout le bloc ou juste de cibler certaines méthodes. J’ai cru comprendre que c’etait mieux de cibler, mais ca alourdit quand meme pas mal le code.

Trop theorique, j’ai pas compris.

Oui sauf que c’est moi qui fait la boite, c’est MA BOITE A MOI!

la aussi j’ai pas tout compris mais en gros, si ma methode toto() renvoie string au debut et que apres elle change et renvoie int, ca va etre un cauchemard. J’ai bon ou j’ai rien capte encore?
D’une maniere generale, si je fais une fonction « drawtruc », j’ai le droit de l’implementer comme je veux du moment qu’elle fait ce pour quoi elle est prevue, nan?

En tout cas, merci a tous pour l’aide, c’est pas encore bien clair mais y a pas de raison que j’y arrive pas :smiley:

LoneWolf
La POO, l’univers et le reste.

C’est cool ce topic pour comprendre la POO. Je n’ai fait que lire la théorie et fait un hello world. Pas eu le temps ni l’occasion de m’y mettre plus.

Et ben tes questions à rebours me permettent de mieux comprendre, alors qu’en général les gens ne montrent pas leur questionnement de départ sur la POO. Ils partent du fait que c’est un fait acquis.

En ce qui concerne un de tes questions de complexification inutile pour un code à toi, moi d’après ce que je comprend de la POO, je le vois comme pouvoir un jour passer après toi en maintenance ou évolution, et hériter et surcharger ton objet en rajoutant mes fonctionnalités, sans remettre les mains dans le cambouis de l’objet d’origine que tu as créé. ça c’est un vrai plus de la POO, et pas que pour la beauté du geste de faire de la POO pour faire de la POO.

Une exception c’est une erreur qui est généré et qui va se balader dans toute ton application, de méthode en méthode jusqu’à être rattrapée.

Un exemple pour savoir où attraper une erreur : tu dois parcourir un fichier de 1000 lignes et récupérer sur chaque ligne un chiffre. L’erreur qui peut se produire c’est qu’une ligne ne contiennent pas de chiffre mais la chaine de caractères : « !#$ » Ou souhaites-tu gérer cette erreur ?

  • Au niveau de la ligne pour pouvoir continuer à lire le fichier même en cas d’erreurs, tu met ton try catch sur la convertion
  • Au niveau du fichier car si le fichier est corrompu ça sert à rien de le lire, tu met ton try catch sur la boucle de lecture
  • Au niveau de l’interface graphique car en cas d’erreurs tu veux veux prévenir l’utilisateur, tu ne captures pas l’erreurs mais tu la propage à la méthode appelante

[quote]la aussi j’ai pas tout compris mais en gros, si ma methode toto() renvoie string au debut et que apres elle change et renvoie int, ca va etre un cauchemard. J’ai bon ou j’ai rien capte encore?
D’une maniere generale, si je fais une fonction « drawtruc », j’ai le droit de l’implementer comme je veux du moment qu’elle fait ce pour quoi elle est prevue, nan?[/quote]
J’ai au boulot un cas d’école qui pourras t’éclairer. Sur une une application de gestion, j’ai une méthode qui s’appelle Integer getStock().

La bonne implémentation que j’aurais développé :

Retourner le stock

La mauvaise implémentation qui a été choisi :

Vérifier la date de mise à jour de stock Appeler le service de mise à jour de stock avec un web service sur un système distant sur une autre base de données Lancer le batch de réapprovision de stock Mettre à jour pleins d'autres trucs qui n'ont aucun rapport avec le stock Retourner le stock

Bref, lorsque tu veux récupérer ton stock, tu dois être conscient que derrière il se passe pleins de trucs pour pouvoir gérer les cas d’erreurs, savoir que tel variable a été mise à jour, c’est juste une horreure.

[quote=« phili_b, post:17, topic: 50983 »]C’est cool ce topic pour comprendre la POO. Je n’ai fait que lire la théorie et fait un hello world. Pas eu le temps ni l’occasion de m’y mettre plus.

Et ben tes questions à rebours me permettent de mieux comprendre, alors qu’en général les gens ne montrent pas leur questionnement de départ sur la POO. Ils partent du fait que c’est un fait acquis.[/quote]
Ah ben tu peux lire de la doc sur la POO, si tu la pratique pas, c’est pas un fait acquis (a mon avis)

En fait je pense qu’inconsciament, je mets le doigt sur ce qu’on a pas reussi a m’expliquer jusqu’a present, et qui se resume a: Pourquoi faire simple quand on peut faire compliquer?
Alors ok j’abuse mais c’est quand meme un peu ca. Ca a une reelle justification sur des gros projet, ou meme des petits projets, a partir du moment ou il y a plusieurs personnes dedans. Mais quand c’est un petit projet, ca me parait pas utile de l’imposer.
Au contraire meme, c’est sur ces petits projets ou il est formateur de laisser faire et de voir le mec se prendre la tete sur un truc qu’il n’avait pas prevu. Et apres il prendra l’habitude d’utiliser les regles de nommage, les proprietes et tout ca.

En fait, c’est exactement ma demarche :smiley:

[quote=« ZGoblin, post:18, topic: 50983 »]Une exception c’est une erreur qui est généré et qui va se balader dans toute ton application, de méthode en méthode jusqu’à être rattrapée.

Un exemple pour savoir où attraper une erreur : tu dois parcourir un fichier de 1000 lignes et récupérer sur chaque ligne un chiffre. L’erreur qui peut se produire c’est qu’une ligne ne contiennent pas de chiffre mais la chaine de caractères : « !#$ » Ou souhaites-tu gérer cette erreur ?

  • Au niveau de la ligne pour pouvoir continuer à lire le fichier même en cas d’erreurs, tu met ton try catch sur la convertion
  • Au niveau du fichier car si le fichier est corrompu ça sert à rien de le lire, tu met ton try catch sur la boucle de lecture
  • Au niveau de l’interface graphique car en cas d’erreurs tu veux veux prévenir l’utilisateur, tu ne captures pas l’erreurs mais tu la propage à la méthode appelante[/quote]
    Y a un piege nan? :smiley:
    Bon perso j’ai un soft qui lit un fichier texte et je fais pas de try catch sur la donnees lu (sur le open et le read, ouais) car, quand ca doit etre un entier, je fais un int.parse() qui a le bon gout de renvoyer false s’il ne peut pas convertir. Moi j’aurais tendance a le mettre sur la ligne donc, et de propager sur l’IU: « l’element truc n’est pas valide, il n’est pas utilise » quand on gere par ligne et « fichier corrompu, va mourir luser » quand le recovery est impossible sur le fichier.

[quote=« ZGoblin, post:18, topic: 50983 »]J’ai au boulot un cas d’école qui pourras t’éclairer. Sur une une application de gestion, j’ai une méthode qui s’appelle Integer getStock().

La bonne implémentation que j’aurais développé :

Retourner le stock

La mauvaise implémentation qui a été choisi :

Vérifier la date de mise à jour de stock Appeler le service de mise à jour de stock avec un web service sur un système distant sur une autre base de données Lancer le batch de réapprovision de stock Mettre à jour pleins d'autres trucs qui n'ont aucun rapport avec le stock Retourner le stock

Bref, lorsque tu veux récupérer ton stock, tu dois être conscient que derrière il se passe pleins de trucs pour pouvoir gérer les cas d’erreurs, savoir que tel variable a été mise à jour, c’est juste une horreure.[/quote]
ah, on a pas la meme definition de implementation (mais je me trompe peut etre).
J’ai pas appris les regles de nommage de C# mais, comme je le disais plus haut, j’ai appris « ca doit dire quelque chose » et notamment pour une fonction, on doit avoir une idee de ce que fait la fonction.
La, c’est pas un probleme d’implementation mais un probleme de nommage de la methode. Elle devrait s’appeler Check_Update_whateva_getStock() nan? :slight_smile: Ou un probleme de « separation of concerns » aussi (ca j’ai bien compris, merci gimly).
D’ailleurs, pour moi, l’implementation c’est pas CE QUE TU FAIS mais COMMENT TU LE FAIS. getStock, ie aller lire le stock, tu peux le coder de plusieurs maniere differente: lire la valeur de l’objet, aller lire la valeur sur l’autre base de donnees, etc, ca reste « getStock ».

Je sais pas comment ca marche chez toi mais j’ai plus l’impression de voir The Dark Side de l’objet, ou on definit getStock qui recupere le stock, et apres on se dit « ah ouais mais faut mettre a jour avant nan? ouais on le rajoute dans getStock, c’est plus simple a utiliser », et apres on se dit « ah oui mais y a aussi l’autre bdd, faut aller la voir! getstock? Yeah getstock! » etc etc.

LoneWolf
Je note, je note :slight_smile:

[quote=« LoneWolf, post:19, topic: 50983 »]Y a un piege nan? :smiley:
Bon perso j’ai un soft qui lit un fichier texte et je fais pas de try catch sur la donnees lu (sur le open et le read, ouais) car, quand ca doit etre un entier, je fais un int.parse() qui a le bon gout de renvoyer false s’il ne peut pas convertir. Moi j’aurais tendance a le mettre sur la ligne donc, et de propager sur l’IU: « l’element truc n’est pas valide, il n’est pas utilise » quand on gere par ligne et « fichier corrompu, va mourir luser » quand le recovery est impossible sur le fichier.[/quote]

Dans mon exemple j’étais parti du principe qu’un parseInt puisse levée l’exception NumberFormatException.
Sinon, non aucun piège, les 3 solutions sont corrects, elles ne font pas la meme choses c’est tout. En pratique la méthode qui va lire le fichier pourra levée une erreur spécifique que l’on aura écrite pour l’occasion et l’on va encapsuler toute les erreurs techniques dans cette nouvelle exception comme ca le jour ou tu veux gérer un nouveau cas d’erreur tu n’auras pas a changer l’API et se sera transparant pour le code appelant.

Et quand je t’entend dire que tu es tout seul sur ton appli donc que l’objet n’est pas nécessaire sache que la séparations en couche/composants te permettra de faire grossir ton application et de faciliter la maintenance, d’en améliorer l’évolutivité, meme si tu es tout seul sur ton appli.