JeuWeb - Crée ton jeu par navigateur
Valueobject - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Valueobject (/showthread.php?tid=7392)

Pages : 1 2 3 4 5 6 7 8


RE: Valueobject - srm - 02-09-2015

Et en Scala, comme d'habitude c'est super simple :


case class Numero(value: Int) {
    require(value > 0, "Le numéro doit être positif")
}

case class Rue(value: String) {
    require(value.length > 0, "La rue ne doit pas être une chaîne vide")
}

case class Ville(value: String) {
    require(value.length > 0, "La ville ne doit pas être une chaîne vide")
}

case class Adresse(numero: Numero, rue: Rue, ville: Ville) {
    override def toString = numero.value + " " + rue.value + " " + ville.value
}

val adresse_de_jean = Adresse(Numero(44), Rue("de la mairie"), Ville("Paris"))
println("Jean habite au " + adresse_de_jean);

val adresse_de_bob = Adresse(Numero(44), Rue("de la mairie"), Ville("Paris"))

if (adresse_de_bob == adresse_de_jean) {
    println("Adresses identiques");
} else {
    println("Adresses différentes");
}



RE: Valueobject - Max72 - 02-09-2015

La vache, vous êtes vraiment des 'Posting Freak' ! On s'en va 3H et y'a une page en plus ^^
C'est parti :
niahoo a écrit :Effectivement, plutôt qu'une interface, je ferais plutot une abstract class avec une exception dans la méthode __set.
Les classes abstraites je les réserves à autre chose : le numéro de rue pourrait très bien étendre une classe abstraites Integer, avec les fonctions communes déjà implémentées, comme :
Code PHP :
<?php 
abstract class ValueObjectInteger
{
  private $number;

  public function __construct($number)
  {
    if (!is_int($number))
    {
      throw new InvalidArgumentException('le nombre doit être un entier');
    }
    $this->number = $number;
  }

  public function __set($nom, $valeur)
  {
    throw new Exception('Tentative de modification du ValueObject Integer');
  }

  public function isEqual(ValueObjectInterface $number)
  {
    if (!$number instanceof $this)
    return false;

    return ($this->number === $number->number);
  }

  public function __toString()
  {
    return strval($this->number);
  }

}

Du coup ma classe Numero serait uniquement ceci :
Code PHP :
<?php 
class Numero extends ValueObjectInteger implements ValueObjectInterface

{
}

Et on pourrait faire la même pour la rue, la ville etc avec une classe abstraite String.

Xenos a écrit :Je te confirme: c'est une mauvaise idée. Masquer les erreurs ainsi, c'est autoriser leur démultiplication et la mort direct du projet quand ces erreurs seront nombreuses et surtout impistables (mais mais! mon code fait n'importe quoi! pourtant y'a pas d'erreur...)
EN effet j'avais vu le problème dans l'autre sens, je prend note.

Xenos a écrit :Oui, dans le cas de la longitude, je suis d'accord car deux valeurs de longitude égales, c'est deux longitudes égales (en partant du postulat qu'on ne considère qu'une seule planète). Dans le cas des rues, c'est différent: deux rues de même nom sont deux entités différentes.

Là, c'est pour moi, c'est comme si tu comparais deux billets sur la base de leur seule valeur faciale: deux billets de 100 ne sont pas forcément les mêmes car la monnaie (ou la ville) peut différer.
Mauvais exemple en effet.

niahoo a écrit :Bah faut pas pousser, faut penser au cas d'utilisation quand même. Qui va comparer deux adresses juste sur le nom de la rue ?
Complètement d'accord (Xenos, tu vas toujours trop loin :p )

Xenos a écrit :Donc, il ne faut pas de méthode "isEqual()" pour la classe "Rue" si on considère que cela ne fait pas sens de comparer deux rues. Je Trouve que c'est c'est là le drame de beaucoup de projets "objets": on crée des classes avec des méthodes qui n'ont de sens que dans un contexte d'utilisation particulier.

Soit la méthode "Rue::isEqual()" existe, est fiable et ne compare que deux rues sans se soucier de "pourquoi est-ce que cette méthode est appelée / dans quelle cas est-elle appelée" (donc, se baser sur le seul nom de rue est léger, ou alors il faut que la classe représente un NomDeRue et non une Rue, puisqu'une Rue n'est pas représentée par son seul nom), soit la méthode n'existe pas (voire, la classe n'existe pas si elle est "interne" à la classe Adresse).
Il faut une méthode "isEqual()" pour la classe Rue puisqu'il faut bien la comparer à une autre Rue. Elle porte le même nom, alors elle est égale.
Comment vois-tu la chose avec la classe Numéro ? Il s'agit simplement d'un Int. Mais si l'on suit ton raisonnement, il faudrait vérifier le numéro, la rue, la ville. C'est ce que fait ma classe Adresse.
Pour que ce soit plus propre, il faudrait que la méthode isEqual() de Rue ne puisse être appelée que par un objet Adresse, ça je suis d'accord.

Voilà pour moi !

PS : Bien que je ne comprenne pas tout, j'aime bien la syntaxe de ton langage Niahoo Smile


RE: Valueobject - niahoo - 02-09-2015

@Max72 ta classe value integer peut elle même étendre une classe abstraite. L'idée est de bloquer les setters et cela devrait se faire à un seul endroit.

@srm Tu as oublié de comparer les noms de ville en lowercase Smile

Enfin, les numéros de rue sont des String.

edit: les case class qui n'ont qu'un seul membre ont une fonction toString définie automatiquement qui output ce membre ?


RE: Valueobject - Xenos - 02-09-2015

Qui va comparer deux adresses juste sur le nom de la rue ? // Elle porte le même nom, alors elle est égale. // Xenos, tu vas toujours trop loin

Je vous parie que sur le long terme, dans quelques années, vous allez avoir besoin de comparer deux rues de deux villes, vous allez être content de voir qu'il existe une classe "Rue" avec une méthode "isEquals()", et vous allez vous arracher les cheveux quand il faudra faire en sorte que deux rues de même nom de deux villes ne soient pas considérées comme identiques. A moins qu'on ne puisse me proposer une méthode non-destructive des API existantes et qui ferait cette comparaison.


Citation :Pour que ce soit plus propre, il faudrait que la méthode isEqual() de Rue ne puisse être appelée que par un objet Adresse, ça je suis d'accord.
Nope, c'est le principe de l'OO: n'importe qui/quoi peut demander un truc à une classe (aka appeler la méthode de l'objet). Si tu commences à vouloir restreindre "qui appelle la méthode", tu vas dans le mur (en tous cas, en PHP). Accessoirement, tu t'assoies sur la combinatoire (le truc génial là, qui fait qu'avec 10 classes t'as 100 assemblages possibles).

Si une méthode de classe A n'a vocation à être appelée que par une seule classe B, alors A est trop fortement couplée à B, et les deux classes ne devraient pas être séparées.



@srm Ca compare quoi, le "==" en fin de ton Scala? Les valeurs des membres? Ou le résultat du toString?

Parce que je me demande ce que ceci donnerait:


val adresse_de_jean = Adresse(Numero(2), Rue("Jean André"), Ville("Bouzy Foissons"))
val adresse_de_bob = Adresse(Numero(2), Rue("Jean Adré Bouzy"), Ville("Foissons"))

if (adresse_de_bob == adresse_de_jean) {
println("Adresses identiques ?!");

Ah, l'injection... ^^


RE: Valueobject - niahoo - 02-09-2015

srm ça compile pas ton truc

(02-09-2015, 04:54 PM)Xenos a écrit : Si une méthode de classe A n'a vocation à être appelée que par une seule classe B, alors A est trop fortement couplée à B, et les deux classes ne devraient pas être séparées.

Ou bien A devrait être définie dans B :p

Citation :vous allez vous arracher les cheveux quand il faudra faire en sorte que deux rues de même nom de deux villes ne soient pas considérées comme identiques.

J'ai vraiment du mal à imaginer ce cas ! Là on bosse sur des value objects qui transportent des données. pas sur des modèles ou autre. Mais bon oui dans l'absolu si le pape change de sexe et que des alien agoraphobes débarquent, ça pourra toujours un jour poser problème. ça sera pas dur à mettre à jour Smile


RE: Valueobject - Xenos - 02-09-2015

Ouep, comme cela est autorisé en Java. Mais pas en PHP.


RE: Valueobject - niahoo - 02-09-2015

Citation :Ah, l'injection...

Il a mis des espaces hein !


RE: Valueobject - Max72 - 02-09-2015

niahoo a écrit :Enfin, les numéros de rue sont des String.

edit: les case class qui n'ont qu'un seul membre ont une fonction toString définie automatiquement qui output ce membre ?
Pas compris

Xenos a écrit :Nope, c'est le principe de l'OO: n'importe qui/quoi peut demander un truc à une classe (aka appeler la méthode de l'objet). Si tu commences à vouloir restreindre "qui appelle la méthode", tu vas dans le mur (en tous cas, en PHP). Accessoirement, tu t'assoies sur la combinatoire (le truc génial là, qui fait qu'avec 10 classes t'as 100 assemblages possibles).

Si une méthode de classe A n'a vocation à être appelée que par une seule classe B, alors A est trop fortement couplée à B, et les deux classes ne devraient pas être séparées.
Je crois que tu n'as pas compris le sens : Rue pourrait être une classe enfant d'Adresse, et sa méthode isEqual() passerait en protected. Ainsi, seule Adresse peut appeler cette méthode. Ca créé quand même du couplage mais nécessaire (comme dans l'exemple actuel).


RE: Valueobject - Xenos - 02-09-2015

J'ai édité:


val adresse_de_jean = Adresse(Numero(2), Rue("Jean André"), Ville("Bouzy Foissons"))
val adresse_de_bob = Adresse(Numero(2), Rue("Jean Adré Bouzy"), Ville("Foissons"))

Wink

Citation :Rue pourrait être une classe enfant d'Adresse, et sa méthode isEqual() passerait en protected. Ainsi, seule Adresse peut appeler cette méthode. Ca créé quand même du couplage mais nécessaire (comme dans l'exemple actuel).

J'ai un doute... Si tu as un typehinting quelque part genre setAdresseJoueur(Adresse $adresse), alors tu peux lui passer une Rue...


RE: Valueobject - niahoo - 02-09-2015

(02-09-2015, 05:07 PM)Max72 a écrit :
niahoo a écrit :Enfin, les numéros de rue sont des String.

edit: les case class qui n'ont qu'un seul membre ont une fonction toString définie automatiquement qui output ce membre ?
Pas compris

Et ben pour la première phrase : « 1 bis rue des machin truc »

Pour la seconde, c'est pour srm. soit il a eu la flemme d'implémenter toString pour ses 3 sous-classes, soit c'est automatique. C'est ce que je voudrais savoir. Mais ça compile pas et j'ai pas de REPL scala pour tester un script.