Exercices dirigés NFP121


Les patrons Memento et Command


Le projet BlueJ

Un Entier... un Memento... un Gardien...cf. le cours, un entier conserve un historique de toutes ses valeurs, le memento sauvegarde l'état d'un entier, le gardien contient l'historique de toutes les sauvegardes (i.e. memento)

La classe Entier est à compléter, seules les méthodes de sauvegarde saveToMemento et de restitution restoreFromMemento sont à écrire. Les classes Memento et Caretaker sont à créer, les classes de tests unitaires, à lire attentivement, sont ci-dessous

public class Entier {
  private int valeur;
  
  public Entier(int valeur){
    this.valeur = valeur;
  }
  
  public void inc(){
    if(valeur==Integer.MAX_VALUE)
        throw new RuntimeException("MAX_VALUE atteinte...");
    this.valeur++;
  }
  
  public void dec(){
    if(valeur==Integer.MIN_VALUE) 
        throw new RuntimeException("MIN_VALUE atteinte...");
    this.valeur--;
  }
  
  public void setValeur(int valeur){
    this.valeur = valeur;
  }
  
  public Memento saveToMemento() { 
    return null; // à compléter
  }
  
  public void restoreFromMemento(Memento m) {
    // à compléter
  }
  
  public int getValeur(){
    return this.valeur;
  }
 
  public String toString(){
    return "<Entier:" + valeur +">";
  }
}

 

 

La classe de tests unitaires EntierTest pourrait être complétée.

public class EntierTest extends junit.framework.TestCase{
 
	public void testSauvegardeRestitution(){
	  Entier e = new Entier(5);
	  assertEquals(5, e.getValeur());
	  Memento memento = e.saveToMemento();
	  e.inc();
	  assertEquals(6, e.getValeur());
	  e.restoreFromMemento(memento);
	  assertEquals(5, e.getValeur());
	}
	
	public void testBorneMin(){
	  Entier e = new Entier(Integer.MIN_VALUE);
	  e.inc();
	  e.dec();
	  try{
	    e.dec();
	  }catch(Exception exc){
	    assertTrue(exc instanceof RuntimeException);
	  }
	}

	public void testBorneMax(){
	  Entier e = new Entier(Integer.MAX_VALUE);
	  e.dec();
	  e.inc();
	  try{
	    e.inc();
	  }catch(Exception exc){
	    assertTrue(exc instanceof RuntimeException);
	  }
	}
}

  La classe de tests unitaires MementoTest pourrait être complétée.

public class MementoTest extends junit.framework.TestCase{
 
	public void testSauvegardeRestitution(){
	  Entier e = new Entier(5);
	  Memento memento = new Memento(e);
	  e.inc();
	  assertEquals(6, e.getValeur());
	  assertEquals(5, memento.getSavedState());
	}
	
	public void testExceptionRestitution(){
	  Entier e = new Entier(Integer.MAX_VALUE);
	  assertEquals(Integer.MAX_VALUE, e.getValeur());
	  Memento memento = null;
	  try{
	    memento = new Memento(e);
	    e.inc();
	  }catch(Exception exc){
	    e.restoreFromMemento(memento);
	  }
	  assertEquals(Integer.MAX_VALUE, e.getValeur());
	}
}

  La classe de tests unitaires CaretakerTest pourrait être complétée.

public class CaretakerTest extends junit.framework.TestCase{
 
	public void testSauvegardeRestitution(){
	  Caretaker gardien = new Caretaker();
	  Entier e = new Entier(5);
	  assertEquals(5, e.getValeur());
	  gardien.setMemento(e.saveToMemento());
	  e.inc();
	  assertEquals(6, e.getValeur());
	  gardien.setMemento(e.saveToMemento());
	  e.inc();
	  assertEquals(7, e.getValeur());
	  e.restoreFromMemento(gardien.getMemento());
	  assertEquals(6, e.getValeur());
	  e.restoreFromMemento(gardien.getMemento());
	  assertEquals(5, e.getValeur());
	  try{
	    e.restoreFromMemento(gardien.getMemento());
	    fail("pas de sauvegarde et une restitution ???"); 
	  }catch(Exception exc){
	   // une exeception a eu lieu... laquelle ? à affiner
	  }
	}
	
	public void testExceptionRestitution(){
	  Caretaker gardien = new Caretaker();
		Entier e = new Entier(5);
	  try{
	    gardien.setMemento(e.saveToMemento());
	    e.setValeur(Integer.MAX_VALUE);
	    gardien.setMemento(e.saveToMemento());
	    e.inc();
	    gardien.forget();
	  }catch(Exception exc){
	    e.restoreFromMemento(gardien.getMemento());
	    assertEquals(Integer.MAX_VALUE, e.getValeur());
	  }
	  e.restoreFromMemento(gardien.getMemento());
	  assertEquals(5, e.getValeur());
	}
}

 

QUESTION1: Complétez la classe Entier, proposez les classes Memento et Caretaker.

public class Caretaker{
  
  public Caretaker(){
  }
  
  public Memento getMemento(){
    return null;
  }

  public void setMemento(Memento memento){
    
  }
  
  public void forget(){
    
  }
}

QUESTION2: Le patron Command

Le projet BlueJ/suite

La classes abstraite Command et la classe de tests unitaires InvokerTest sont fournies,

public abstract class Command{

  public abstract void execute() throws Exception;
  public abstract void undo() throws Exception;
  
  public void executeTransaction() throws Exception{
    try{
      execute();
    }catch(Exception e){
      undo();
      throw e;
    }
  }
}

 

 La classe de tests unitaires InvokerTest pourrait être complétée.

 

public class InvokerTest extends junit.framework.TestCase{
 
  public void testInvokerIncDec(){
    Entier e = new Entier(5);
    Command inc = new IncCommand(e);
    Command dec = new DecCommand(e);
    SetValeurCommand set = new SetValeurCommand(e);
     
    Invoker invoker = new Invoker(inc,dec,set);
    try{
      assertEquals(5, e.getValeur());
      invoker.inc();
      assertEquals(6, e.getValeur());
      invoker.inc();
      assertEquals(7, e.getValeur());
      
      set.setValeur(Integer.MAX_VALUE);
      invoker.set();
      assertEquals(Integer.MAX_VALUE, e.getValeur());
    }catch(Exception exc){
      fail("aucune exception n'est attendue ???");
    }
  }
  
  
  public void testInvokerException(){
    Entier e = new Entier(Integer.MAX_VALUE);
    Command inc = new IncCommand(e);
    Command dec = new DecCommand(e);
    SetValeurCommand set = new SetValeurCommand(e);
     
    Invoker invoker = new Invoker(inc,dec,set);
    try{
      assertEquals(Integer.MAX_VALUE, e.getValeur());
      invoker.inc();
      fail("une exception est attendue ???");
    }catch(Exception exc){
      assertEquals(Integer.MAX_VALUE, e.getValeur());
    }
    try{
      set.setValeur(Integer.MIN_VALUE);
      invoker.set();
      assertEquals(Integer.MIN_VALUE, e.getValeur());
      invoker.dec();
      fail("une exception est attendue ???");
    }catch(Exception exc){
      assertEquals(Integer.MIN_VALUE, e.getValeur());
    }
  }
}

QUESTION2 Proposez la classe Invoker puis les 3 commandes concrètes IncCommand, DecCommand et SetValeurCommand

Post-liminaire : Préparation du tp_commit, exécution et tests de l'applette de l'énoncé

console> appletviewer http://jfod.cnam.fr/progAvancee/tp_commit/tp_commit.html
avec si nécessaire sous windows set PATH=D:\BlueJ-315\jdk\bin;%PATH%

Depuis votre navigateur http://jfod.cnam.fr/progAvancee/tp_commit/tp_commit.html

 


/* Une idée...