Showing posts with label patron. Show all posts
Showing posts with label patron. Show all posts

Thursday, October 11, 2012

Patron : Prototype


Le patron prototype est de type création.
Il est utilisé lorsque la création d'un objet est complexe et consommatrice de temps. Pour cela, on crée juste une instance et on la clone.
Le fait de ne pas utiliser de "new Xxx()" et d'initialiser des propriétés fait gagner beaucoup de temps.

Admettons que nous sommes Saroumane et on veut construire une armée de monstres (orques et wargs) le plus rapidement possible pour combattre Sauron.
On peut faire naitre des orques ("Montre x = new Monstre()") mais cela prendrait beaucoup de temps, car on devra attendre qu'ils atteignent l'age adulte pour pouvoir se battre.
L'autre solution, et de prendre l'orque le plus fort et de le cloner! C'est beaucoup plus rapide!


Ici, la classe Monstre est une sous-classe de Cloneable et doit posséder une fonction "clone()".

Magicien.java
import java.util.ArrayList;
import java.util.Iterator;

public class Magicien {
 public static void main(String[] args) {
  Magicien saroumane = new Magicien();
  saroumane.construireArmee();
 }
 
 public Magicien() { }
 
 public void construireArmee() {
  Monstre orque = new Orque();
  orque.setName("Chef orque");
  Monstre warg = new Warg();
  orque.setName("Chef warg");
  
  Monstre monstreCloned;
  ArrayList armee = new ArrayList();
  
  // on va creer 10 soldats : 5 orques et 5 wargs
  for(int i = 0; i < 10; i++) {
   if(i%2 == 0) {
    monstreCloned = orque.clone();
    monstreCloned.setName("soldat orque " + i);
   } else {
    monstreCloned = warg.clone();
    monstreCloned.setName("soldat warg " + i);
   }
   
   armee.add(monstreCloned);
  }
  
  Iterator it =  armee.iterator();
  
  while(it.hasNext()){
   monstreCloned = it.next();
   System.out.println(monstreCloned.getName());
  }
 }
}
//ignorer les 3 balises ci-dessous
Monstre.java
public abstract class Monstre implements Cloneable{
 protected String name;
 
 public Monstre clone() {
  try {
   Monstre clone = (Monstre)super.clone();
   clone.name = this.name;
   return clone;
  } catch (CloneNotSupportedException e){
   return null;
  }
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }
}
Orque.java
public class Orque extends Monstre{ }

Warg.java
public class Warg extends Monstre{ }


Le résultat de l'execution est:

soldat orque 0
soldat warg 1
soldat orque 2
soldat warg 3
soldat orque 4
soldat warg 5
soldat orque 6
soldat warg 7
soldat orque 8
soldat warg 9

Et voila, maintenant Saroumane est prêt à partir en guerre!

Friday, October 5, 2012

Patron : Fabrique (factory)

Le patron Fabrique (Factory en anglais) est un patron de type conception.

Ce patron contient une classe qui fait appel à une fabrique pour créer des objets sans connaitre la classe exacte de ces objets. Pour déterminer la classe exacte, un paramètre est passé lors de l'appel.



Description des classes :

  • Fabrique : la fabrique en charge de créer les objets selon le paramètre recu 
  • Race : classe abstraite 
  • Humain, Orc, Elf : classes fille de Race 
  • Jeu : classe principale qui ne se preocupe pas de quel type de race sont les objets qu'elle manipule 



Dans l'exemple ci-dessous, la classe Jeu fait appel à la classe Fabrique. La classe Jeu ne connais pas les sous-classes de Race.
La responsabilité de créer le bon objet est laissé à la classe Fabrique. Cela fait moins de ligne de code pour la classe Jeu.

Une fois les objets personnagePrincipal, ennemi et ami crées, la classe Jeu traite ces objets comme des objets de type Race.


Jeu.java
public class Jeu {
 
 public static void main(String[] args) {
  Jeu jeu = new Jeu();
  jeu.jouer();
 }
 
 public Jeu() { }
  public void jouer() {
  Fabrique fabrique = new Fabrique();
  
  Race personnagePrincipal = fabrique.getRace("humain");
  action(personnagePrincipal);
  
  Race ennemi = fabrique.getRace("orc");
  action(ennemi);
  
  Race ami = fabrique.getRace("elf");
  action(ami);
 }
 public void action(Race joueur) {
  //on ne se préocupe pas si "joueur" 
  //est un humain ou un orc ou un elf
  joueur.parler();
 }
}
Race.java
public abstract class Race {
  abstract void parler();
}
Humain.java
public class Humain extends Race{
 public Humain() {}
 
 public void parler() {
  System.out.println("Je suis un humain!");
 }
}
Orc.java
public class Orc extends Race{
 public Orc() {}
 
 public void parler() {
  System.out.println("Grrrrrr");
 }
}
Elf.java
public class Elf extends Race{
 public Elf() {}
 
 public void parler() {
  System.out.println("Je suis un elf!");
 }
}
Fabrique.java
public class Fabrique {
 public Fabrique() { }
 
 public Race getRace(String type) {
  Race race;
  
  // ...
  // par exemple: doit faire des trucs 
  // compliqués ici avant la creation d'objet 
  // (verification, initialisation, etc.)
  // ...
  
  if ("humain".equals(type))
   race = new Humain();
  else if ("orc".equals(type))
   race = new Orc();
  else if ("elf".equals(type))
   race = new Elf();
  else
   race = null;
  
  return race;
 }
}



Et sans la Fabrique...

L'exemple est très simple, donc ce n'est pas évident de prouver que sans l'utilisation de ce patron, le code devient plus complexe. Mais je vais essayer.
Voici maintenant le meme code sans la fabrique.
public class NoFactory {

 /**
  * @param args
  */
 public static void main(String[] args) {
  NoFactory noFactory = new NoFactory();
  noFactory.start();
 }
 public NoFactory() { }
 
 public void start() {
  
  // ...
  // par exemple: doit faire des trucs 
  // compliqués ici avant la creation d'objet 
  // (verification, initialisation, etc.)
  // ...
  
  Race personnagePrincipal = new Humain();
  action(personnagePrincipal);
  
  Race ennemi = new Orc();
  action(ennemi);
  
  Elf ami = new Elf();
  action(ami);
 }
 
 public void action(Race joueur) {
  // on ne se préocupe pas si "joueur" 
  // est un humain ou un orc ou un elf
  joueur.parler();
 }
}
Deux choses :

  1. la classe NoFactory doit maintenant s'occuper de faire des trucs compliqués (exemple: verifications, initialisation,etc.) avant la creation des objets 
  2. la classe NoFactory doit connaitre le type exacte des objets. 


J'ai certainement fait des fautes ou écrit des choses pas clair, donc n'hésitez pas laisser un commentaire. Lien Wikipedia : Fabrique