JeuWeb - Crée ton jeu par navigateur
[JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - 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 : [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! (/showthread.php?tid=7068)

Pages : 1 2 3 4 5 6 7 8 9 10 11


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - srm - 03-08-2013

bah figure toi que si, k a bien été responsable de la modification de value.
Puisque c'est bien k qui a modifié value suite à un appel de increment.
Si on avait fait k.value +=1 tu aurais raison, mais ça n'est pas le cas.

Donc le domaine des responsabilités est bien respecté.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - Xenos - 03-08-2013

Si je fais val.increment() dans le callback, tout va bien.
Si je fais val.value += 1 dans le callback, tout va mal.
Donc l'intégrité de la classe de t ne dépend non pas de la classe de t, mais du callback, en dehors de t?! Pourquoi un code extérieur à la classe T aurait le droit de modifier les objets stockés dans les propriétés de T? Ces objets me semblent alors être "partagés" entre T et le code externe.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - srm - 03-08-2013

Si tu veux laisser la responsabilité à k de modifier value, la solution est simple.
Passer la propriété value en privé/protégé Wink

L'intégrité de la classe, c'est son fonctionnement, pas les données qu'elles contiennent.
Ils sont partagés car tu as choisi de les partager en rendant ta classe iterable.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - Xenos - 03-08-2013

D'accord, donc finalement, cela revient à dire que ce que je n'aime pas, c'est rendre une classe itérable... Ca rejoint mon histoire d'atome: si je ne peux pas subdiviser l'objet, je ne peux pas le rendre itérable. De plus, si "rendre Iterable" c'est "partager les données", je trouve que l'encapsulation en prend quand même un sacré coup !

Point de vue sécurité, l'intégrité d'une classe passe aussi par ses données (non?). Ou alors il faut vérifier, au début de chaque méthode, que les données de la classe sont intègres. Ou encore, considérer que la classe implémentant Iterable n'a le droit de ne rien faire sur ses propres données, puisque partagées.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - srm - 03-08-2013

L'encapsulation est très mise à mal avec ta façon de faire, car justement au lieu d'avoir plein d'éléments simple, tu encapsules tout dans une boite noire, donc on peut pas encapsuler ta boite noire dans autre chose, ou avec très peu de souplesse.

On parle jamais de point de vue de sécurité d'un code par rapport à un autre vis à vis d'un même programme Wink

Tiens, reprends ton exemple simple de Bibliothèque en PHP avec un système de traduction qui met tout en majuscule le contenu du livre et met le code ici. Je vais te montrer la problématique de ta façon de coder.

Sans compte et je répète et souligne, ton code est pas testable avec ta façon de procéder.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - Xenos - 03-08-2013

La boite noire gère un gros truc ok, et j'ai des classes avec "beaucoup" de méthodes, mais cela ne la rend pas forcément "in-encapsulable" ailleurs... Ok, c'est pas très souple, car justement, c'est "très sûr" puisque je pousse l'histoire d'intégrité jusqu'aux données elles-mêmes.

Pour l'aspect sécurité, je trouve que c'est mal venu de l'ignorer au sein d'un programme, car le programme ne me semble pas être une "unité", mais un assemblage de classe. Ok, ignorer la sécurité au sein d'une classe car c'st une unité, d'accord, mais au sein d'un programme... Qu'en est-il si j'utilise une bibliothèque externe? Faut que je relise tout le code pour être "sûr qu'elle soit sûre"? En cas de sous-traitance ou d'incompétence d'un membre de l'équipe devant travailler sur une seule classe, on détruit la sécurité de tout le programme?

Ok. le 1er code ou le 2nd? Ou les deux? ou indifféremment?


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - srm - 03-08-2013

Justement, l'objet c'est de faire du code très souple, tu devrais sérieusement lire le tutoriel sur la programmation SOLID que je t'ai donné.

Tu utilises mal le mot sécurité, quand on dit qu'une bibliothèque externe est "sûre", ça sera par exemple qu'elle soit sans bug, sans consommation mémoire excessive, qu'il n'y ai pas de failles de sécurité au niveau entrée/sortie UTILISATEUR (genre formulaire, cookie, etc). C'est pas du tout approprié pour le problème présent.

Un seul code, celui que tu juges le plus pertinent/performant/en adéquation avec ta façon de programmer.


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - niahoo - 03-08-2013

(03-08-2013, 02:13 PM)oxman a écrit : Donc je dis encore heureux qu'il puisse modifier l'objet dans la librairie puisqu'il a demandé l'objet à la librairie pour travailler dessus.
Aucun rapport avec l'encapsulation.

Oui et encore une fois, si tu lis mon code, tu verras que la bibliothèque(ou librairie) contrôle la sortie du callback. Si on renvoie un bouquin, tu peux lui avoir fait ce que tu veux, son rôle est de l'accepter, elle a pas à t'emm*rder. Si par contre tu lui renvoie pas un bouquin, tu peux faire absolument ce que tu veux au bouquin qui passe dans le callback, la bibliothèque conserve la première version du bouquin. (puisque tes modifs sont pas valides).

Citation :Si je fais val.increment() dans le callback, tout va bien.
Si je fais val.value += 1 dans le callback, tout va mal.
Donc l'intégrité de la classe de t ne dépend non pas de la classe de t, mais du callback, en dehors de t?! Pourquoi un code extérieur à la classe T aurait le droit de modifier les objets stockés dans les propriétés de T? Ces objets me semblent alors être "partagés" entre T et le code externe.

Tu as fait de .value un membre public, il faut utiliser des privates, sans quoi ton objet n'est pas pur et donc oui, tu peux faire n'importe quoi.

ah ben je viens de paraphraser oxman ..

Citation :si "rendre Iterable" c'est "partager les données"

rendre itérable c'est permettre à une entité extérieure de parcourir une collection. ça peut être en lecture seule, en modification directe (ce contre quoi nous sommes d'accord), en modification avec contrôle (ce que j'ai proposé). Note que les collections comme celles de Backbone JS sont à mi-chemin, c'est au programmeur de faire quelque chose de propre.

Citation :Point de vue sécurité, l'intégrité d'une classe passe aussi par ses données (non?). Ou alors il faut vérifier, au début de chaque méthode, que les données de la classe sont intègres. Ou encore, considérer que la classe implémentant Iterable n'a le droit de ne rien faire sur ses propres données, puisque partagées.

Dans l'exemple que je donne tu pourrais facilement faire un évènement "humidité" qui détruit un livre de temps en temps. Mais si tu décides que la bibliothèque a les pleins pouvoirs sur tes bouquin, tu devra le considérer comme un conteneur unsafe et prévoir un second conteneur de backup. ça c'est pas la doctrine objet qui décide, c'est le programmeur. Mais personnellement quand j'utilise des collections, je leur demande juste de pourvoir mettre des trucs de côté pour pouvoir les récupérer plus tard ou travailler par lots.

(03-08-2013, 03:34 PM)Xenos a écrit : Pour l'aspect sécurité, je trouve que c'est mal venu de l'ignorer au sein d'un programme, car le programme ne me semble pas être une "unité", mais un assemblage de classe. ...
Ok. le 1er code ou le 2nd? Ou les deux? ou indifféremment?

En l'occurence si tu implémentes toutes les traductions dans ta classe bibliothèque c'est le même responsable moral (mais plusieurs dev possible) qui gère cette classe, donc généralement tu fais confiance à ton propre code (en termes de sécurité, les bugs c'est autre chose, bien que avec ma solution, on gère au moins les bugs qui empêchent de renvoyer un #livre{})


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - Xenos - 03-08-2013

Dans la même classe, oui, ok, je fais confiance à mon code. La modification avec contrôle revient finalement à sortir un élément de la collection, puis en faire re-rentrer un comme n'importe quel autre élément à entrer.
Cela me semble différent de "faire sortir une référence au livre". C'est ça que je n'aime pas, et que Array.forEach() semble faire. Si mon callback stocke cette référence dans une variable globale, je pourrai faire ce que je veux avec l'objet référencé, et le conteneur n'arrivera pas à faire sa vérification interne...

Pour le code (jouons le jeu, faisons full propre comme je ferai un projet final)
Code PHP :
<?php
interface IMAJUSCULES
{
public
/*void*/ function MAJUSCULES();
}
interface
ILivreAjoutable
{
public function
addLivre(/*Livre*/ $p_livre);
}
interface
ILivreRetirable
{
public
/*Livre*/ function getLivre(/*string*/ $p_titre);
}
interface
IBibliotheque extends ILivreAjoutable, ILivreRetirable
{
}
interface
ITitreRecuperable
{
public
/*string*/ function getTitre();
}
interface
ITexteRecuperable
{
public
/*string*/ function getContenu();
}
interface
ILivre extends ITitreRecuperable, ITexteRecuperable
{
}

/*objet*/
class Livre implements ILivre
{
protected
/*string*/ $titre;
protected
/*string*/ $texte;
public function
__construct(/*string*/ $p_titre, /*string*/ $p_texte)
{
$this->titre = $p_titre;
$this->texte = $p_texte;
}
public
/*string*/ function getTitre()
{
return (
$this->titre);
}
public
/*string*/ function getContenu()
{
return (
$this->texte);
}
}

/*objet*/
class Bibliotheque implements IBibliotheque
{
protected
/*array[string]*/ $titres;
protected
/*array[string]*/ $textes;

public function
__construct()
{
$this->titres = array();
$this->textes = array();
}
public function
addLivre(/*Livre*/ $p_livre)
{
$this->titres[] = $p_livre->getTitre();
$this->textes[] = $p_livre->getContenu();
}
public
/*Livre*/ function getLivre(/*string*/ $p_titre)
{
$index = array_search($p_titre, $this->titres);
unset(
$this->titres[$index]);
unset(
$this->textes[$index]);
return (new
Livre($this->titres[$index], $this->textes[$index]));
}
}

//-----------------------
class MonLivre extends Livre implements IMAJUSCULES
{
public
/*void*/ function MAJUSCULES()
{
$this->titre = strtoupper($this->titre);
$this->texte = strtoupper($this->texte);
}
}

class
MaBibliotheque extends Bibliotheque implements IMAJUSCULES
{
public
/*void*/ function MAJUSCULES()
{
// Comme mes données sont totalement miennes, j'en fais ce que je veux
if (mt_rand(0, 100) > 50)
{
echo(
'I use array_map<br/>');
$this->titres = array_map("strtoupper", $this->titres);
$this->textes = array_map("strtoupper", $this->textes);
}
else
{
echo(
'I new MonLivre()<br/>');
$livres = array();
foreach (
$this->titres as $key=>$titre)
{
$livre = new MonLivre($titre, $this->textes[$key]);
$livre->MAJUSCULES();
$livres[] = $livre;
}
$this->titres = array();
$this->textes = array();
foreach (
$livres as $livre)
{
$this->titres[] = $livre->getTitre();
$this->textes[] = $livre->getContenu();
}
}
}
}

// Main
$myBook = new Livre('Lorem Ipsum', 'Lorem ipsum dolor sit amet, consectetur adipisicing elit,...');

$bibliotheque = new MaBibliotheque();
$bibliotheque->addLivre($myBook);
$bibliotheque->MAJUSCULES(); // Bibliothèque, débrouilles-toi !
// $myBook est resté en minuscules !
// C'est le contenu de la Bibliothèque qui est passé en majuscules.
var_dump($bibliotheque);
?>

Single Responsability: MaBibliothèque a la responsabilité de gérer le paquet de Livres dans son ensemble.
Open/Close principle: Mes modifications ont été faites en aval (ok, mes attributs n'auraient pas du être "private" d'origine)
Liskov substitution principle: Ok
Interface segregation principle: Corrigé (c'est vrai que je n'utilise pas assez les interfaces)
Depency injection: C'est l'un de ceux avec lequel j'ai le plus de mal (et avec lequel je ne suis pas d'accord), puisque via cette dépendance, le développeur peut avoir une porte "d'entrée" dans la classe (avec new Bibliotheque($myConteneur = new Conteneur()) qui permet alors de traiter le conteneur de Bibliothèque à travers $myConteneur).


RE: [JS] Boucle for..in Array et ajout de methodes via prototype = conflit?! - srm - 03-08-2013

Single Responsability : Non, ta classe MaBibliothèque genre les livres et la traduction.
Open/Close principle : Non, tu as du créer une nouvelle classe pour prendre en compte la traduction qui encapsule ta classe existante, donc partout dans ton code ou tu avais Bibliotheque tu as du remplacer par MaBibliotheque pour pouvoir utiliser la traduction.
Liskov substitution principle : Oui, j'ai l'impression en regardant vite fait.
Interface segregation principle : Oui
Dependency Injection : Non, le développeur aura forcément une porte d'entrée quoi que tu fasses. Même dans ton code j'ai une porte d'entrée si je veux. Réfléchir de cette façon n'est PAS la bonne solution, ça n'a pas de sens.

Pourquoi dans Bibliotheque tu ne stocks pas le livre directement mais chaque propriété du livre séparément ?
Tu as bien plus de chance d'avoir des bugs et soucis.

Et pour preuve :

unset($this->titres[$index]);
unset($this->textes[$index]);
return (new Livre($this->titres[$index], $this->textes[$index]));

Comment tu construis un livre avec des paramètres que tu viens de unset ?

La version en Scala :


import scala.collection.mutable.ListBuffer


trait StorageLibrary
{

def store(book: Book): ListBuffer[Book]
def getByTitle(title: String): Option[Book]

}

trait Readable
{

def getTitle: String
def getText: String
def setText(newText: String): Unit

}


case class Book(protected var title: String, protected var text: String) extends Readable
{

def getTitle = title
def getText = text
def setText(newText: String) = text = newText

}


class Storage extends StorageLibrary
{

protected val books = new ListBuffer[Book]

def store(book: Book) = books += book
def getByTitle(title: String): Option[Book] = books.find(_.getTitle == title)

}


class Library(val storage: StorageLibrary)
{

def addBook(book: Book) = storage.store(book)
def getByTitle(title: String): Option[Book] = storage.getByTitle(title)

}

case class Translation(item: Readable)
{

def translate = item.setText(item.getText.toUpperCase)

}



object Main extends App
{

val storage = new Storage
val library = new Library(storage)

val book = Book("Lorem Ipsum", "Lorem ipsum dolor sit amet, consectetur adipisicing elit,...")
val sameBook = Book("Lorem Ipsum", "Lorem ipsum dolor sit amet, consectetur adipisicing elit,...")

library.addBook(book)

val bookFound = library.getByTitle("Lorem Ipsum")

bookFound match {
case None => println("Book not found")
case Some(book) => {
println("Book found : " + book)
println("Book same : " + (book == sameBook))
Translation(book).translate
println("Book translated : " + book)
}
}
}

On peut voir par exemple que ma classe Translation marchera pour autre chose que mes livres.
Tandis que toi, ta classe Translation est encapsulé dans ta Bibliothèque, donc si tu veux l'utiliser ailleurs, tu vas devoir la réencapsulé dans une autre classe, avec les problèmes que ça comporte que j'ai cité.

Moi si j'ai une autre classe, j'aurais rien à faire, juste à utiliser dans mon code Translation(ReadableObject).translate, open/close principle.
Et mon code est testable.