public class Main {
public static void main(String[] args) {
String msg1 = "giallo";
String msg2 = "verde";
String msg3 = "rosso";
MessageHandler msgHander = new MessageHandler();
msgHander.onMessage(msg1);
msgHander.onMessage(msg2);
msgHander.onMessage(msg3);
}
}
class MessageHandler {
void onMessage(String msg) {
if ("giallo".equals(msg)) {
System.out.println("yellow");
} else if ("rosso".equals(msg)) {
System.out.println("red");
} else if ("verde".equals(msg)) {
System.out.println("green");
}
}
}
Innanzitutto dobbiamo introdurre dei test.
per fare ciò però abbiamo bisogno di un refactoring preliminare
passo 1: estrarre i metodi che stampano a video
public void onMessage(String msg) {
if ("giallo".equals(msg)) {
printYellow();
} else if ("rosso".equals(msg)) {
printRed();
} else if ("verde".equals(msg)) {
printGreen();
}
}
protected void printYellow() {
System.out.println("yellow");
}
protected void printRed() {
System.out.println("red");
}
protected void printGreen() {
System.out.println("green");
}
passo 2
isolare la responsabilità di stampare ad una classe Printer
public class MessageHandler {
Pinter printer = new Pinter();
public void onMessage(String msg) {
if ("giallo".equals(msg)) {
printer.printYellow();
} else if ("rosso".equals(msg)) {
printer.printRed();
} else if ("verde".equals(msg)) {
printer.printGreen();
}
}
}
class Pinter {
public void printYellow() {
System.out.println("yellow");
}
public void printRed() {
System.out.println("red");
}
public void printGreen() {
System.out.println("green");
}
}
passo 3 Factory method per l'oggetto printer
public class MessageHandler {
Pinter printer;
public MessageHandler() {
printer = getPinter();
}
...
protected Pinter getPinter() {
return new Pinter();
}
}
passo 4
Per testare la classe MessageHandler possiamo innanzitutto creare una classe stub della classe Printer
public class PrinterStub extends Printer {
public String printedMsg = null;
public void printYellow() {
printedMsg = "yellow";
}
public void printRed() {
printedMsg = "red";
}
public void printGreen() {
printedMsg = "green";
}
}
e poi creare un test
public class MessageHandlerTest extends TestCase {
public void testOnMessage() {
final PrinterStub printerStub = new PrinterStub();
MessageHandler instance = new MessageHandler() {
protected Printer getPinter() {
return printerStub;
}
};
String msg = "giallo";
instance.onMessage(msg);
assertEquals("yellow", printerStub.printedMsg);
}
}
rifattorizziamo il test in modo da rendere la creazione dell'istanza di MessageHandler più semplice.
facciamo diventare printerStub un membro della classe di test e aggiungiamo il factory method hetMessageHandler.
public class MessageHandlerTest extends TestCase {
final PrinterStub printerStub = new PrinterStub();
public void testOnMessage() {
MessageHandler instance = getMessageHandler();
String msg = "giallo";
instance.onMessage(msg);
assertEquals("yellow", printerStub.printedMsg);
}
private MessageHandler getMessageHandler() {
return new MessageHandler() {
protected Printer getPinter() {
return printerStub;
}
};
}
}
possiamo ora rinominare il test testOnMessage in testOnMessageGiallo e aggiungere i test per il caso 'verde' e 'rosso'
public void testOnMessage_giallo() {
MessageHandler instance = getMessageHandler();
String msg = "giallo";
instance.onMessage(msg);
assertEquals("yellow", printerStub.printedMsg);
}
public void testOnMessage_verde() {
MessageHandler instance = getMessageHandler();
String msg = "verde";
instance.onMessage(msg);
assertEquals("green", printerStub.printedMsg);
}
public void testOnMessage_rosso() {
MessageHandler instance = getMessageHandler();
String msg = "rosso";
instance.onMessage(msg);
assertEquals("red", printerStub.printedMsg);
}
definiemo le stringhe costanti
public final String GIALLO = "giallo";
public final String VERDE = "verde";
public final String ROSSO = "rosso";
public final String YELLOW = "yellow";
public final String GREEN = "green";
public final String RED = "red";
final PrinterStub printerStub = new PrinterStub();
public void testOnMessage_giallo() {
MessageHandler instance = getMessageHandler();
String msg = GIALLO;
instance.onMessage(msg);
assertEquals(YELLOW, printerStub.printedMsg);
}
public void testOnMessage_verde() {
MessageHandler instance = getMessageHandler();
String msg = VERDE;
instance.onMessage(msg);
assertEquals(GREEN, printerStub.printedMsg);
}
public void testOnMessage_rosso() {
MessageHandler instance = getMessageHandler();
String msg = ROSSO;
instance.onMessage(msg);
assertEquals(RED, printerStub.printedMsg);
}
muoviamo le variabili statiche YELLOW, GREEN e RED nella classe Printer
public class Printer {
public static final String YELLOW = "yellow";
public static final String GREEN = "green";
public static final String RED = "red";
public void printYellow() {
System.out.println(YELLOW);
}
public void printRed() {
System.out.println(RED);
}
public void printGreen() {
System.out.println(GREEN);
}
}
quindi nella classe di test
public class MessageHandlerTest extends TestCase {
public final String GIALLO = "giallo";
public final String VERDE = "verde";
public final String ROSSO = "rosso";
final PrinterStub printerStub = new PrinterStub();
public void testOnMessage_giallo() {
MessageHandler instance = getMessageHandler();
String msg = GIALLO;
instance.onMessage(msg);
assertEquals(Printer.YELLOW, printerStub.printedMsg);
}
public void testOnMessage_verde() {
MessageHandler instance = getMessageHandler();
String msg = VERDE;
instance.onMessage(msg);
assertEquals(Printer.GREEN, printerStub.printedMsg);
}
public void testOnMessage_rosso() {
MessageHandler instance = getMessageHandler();
String msg = ROSSO;
instance.onMessage(msg);
assertEquals(Printer.RED, printerStub.printedMsg);
}
....
}
Comments (3)
Andrea Rosa said
at 2:29 am on Nov 8, 2009
Ciao Marco,
grazie mille per avere messo il materiale on-line, questo mi ha dato la possibilità di rivederlo e mi vine subito una domanda:
Abbiamo fatto il refactoring con la classe printer e con l'introduzione dello stub però siamo ancora dipendenti dagli "if", mi pare che stavamo discutendo della possibilità di eliminare questa catena di if:
public void onMessage(String msg) {
if ("giallo".equals(msg)) {
printer.printYellow();
} else if ("rosso".equals(msg)) {
printer.printRed();
} else if ("verde".equals(msg)) {
printer.printGreen();
}
}
..come lo si potrebbe fare?
Se non hai tempo di rispondere qui, ne parliamo alla prossima occasione.
Grazie ancora per la tua precisione, chiarezza e passione che metti all'interno del gruppo.
--
Andrea
Bruno Pasquali said
at 6:52 am on Nov 8, 2009
Ciao a tutti
Prima di tutto ringrazio anche io per il materiale on-line e per a serata.
Una soluzione per eliminare gli "if" c'è nel materiale messo on-line da Ivan Gelpi e corrisponde all'uso di una mappa (hasht able) di cui si era disscusso a inizio kata.
Bruno
Ivan Gelpi said
at 9:49 am on Nov 12, 2009
Esatto,
in effetti c'è un metodo ancora migliore, come suggerito anche dal mio collega Nicola Breda, che è alla base di molte tecnologie.
Questo metodo permette non solo di eliminare gli If, ma anche di fare a meno della mappa, istanziando direttamente gli handler in base al nome del messaggio. Per evitare doppioni lo spiego direttamente nella note della pagina http://bergamo-xpug.pbworks.com/Kata+Message+Handler+-+gruppo+2 .
Avevo deciso di scartare questo metodo per disaccoppiare gli handler istanziati rispetto al nome dei messaggi e rendere la cosa più configurabile (grazie alla mappa) ma in effetti nel nostro caso la cosa era perfettamente inutile dato cha abbiamo sempre una corrispondenza tra messaggio e handler. Vi rimando comunque all'altra pagina per la soluzione alternativa.
Ciao
Ivan
You don't have permission to comment on this page.