Wzorce projektowe: Chain of Responsibility
Wzorzec projektowy Chains of Responsibility prowadzi do utworzenia łańcucha obiektów, które analizują żadanie. Analiza przeprowadzana jest kolejno przez każdy z nich. Obiekt może zapewnić obsługę żądania lub przekazuje to żądanie dalej, lub to i to.
1 public class Żądanie { 2 private String title; 3 private int value; 4 5 public Żądanie(String title, int value) { 6 this.title = title; 7 this.value = value; 8 } 9 10 public void print() { 11 System.out.println(title + " " + value); 12 } 13 14 public int getValue() { 15 return value; 16 } 17 } 18
1 public abstract class Łapacz { 2 protected Łapacz następca; 3 4 public void setNastępca(Łapacz łapacz) { 5 następca = łapacz; 6 } 7 8 public abstract void łapŻądanie(Żądanie żądanie); 9 } 10
1 public class ŁapaczNegatywny extends Łapacz { 2 3 public void łapŻądanie(Żądanie żądanie) { 4 if (żądanie.getValue() < 0) { 5 System.out.println("Łapacz negatywny łapie wartości mniejsze niż 0"); 6 żądanie.print(); 7 } else { 8 if (następca != null) 9 następca.łapŻądanie(żądanie); 10 } 11 } 12 } 13
1 public class ŁapaczPozytywny extends Łapacz { 2 3 public void łapŻądanie(Żądanie żądanie) { 4 if (żądanie.getValue() > 0) { 5 System.out.println("Łapacz pozytywny łapie wartości większe niż 0"); 6 żądanie.print(); 7 } else { 8 if (następca != null) 9 następca.łapŻądanie(żądanie); 10 } 11 } 12 }
1 public class ŁapaczNeutralny extends Łapacz { 2 3 public void łapŻądanie(Żądanie żądanie) { 4 if (żądanie.getValue() == 0) { 5 System.out.println("Łapacz neutralny łapie wartości równe 0"); 6 żądanie.print(); 7 } else { 8 if (następca != null) 9 następca.łapŻądanie(żądanie); 10 } 11 } 12 }
1 public class TesterŁapaczy { 2 public static void main(String[] args) { 3 Łapacz łapacz1 = new ŁapaczNegatywny(); 4 Łapacz łapacz2 = new ŁapaczPozytywny(); 5 Łapacz łapacz3 = new ŁapaczNeutralny(); 6 7 łapacz1.setNastępca(łapacz2); 8 łapacz2.setNastępca(łapacz3); 9 10 łapacz1.łapŻądanie(new Żądanie("Wartość negatywna ", -5)); 11 łapacz1.łapŻądanie(new Żądanie("Wartość pozytywna ", 1)); 12 łapacz1.łapŻądanie(new Żądanie("Wartość negatywna ", -1)); 13 łapacz1.łapŻądanie(new Żądanie("Wartość negatywna ", -2)); 14 łapacz1.łapŻądanie(new Żądanie("Wartość neutralna ", 0)); 15 łapacz1.łapŻądanie(new Żądanie("Wartość negatywna ", -1)); 16 łapacz1.łapŻądanie(new Żądanie("Wartość pozytywna ", 1)); 17 łapacz1.łapŻądanie(new Żądanie("Wartość neutralna ", 0)); 18 łapacz1.łapŻądanie(new Żądanie("Wartość pozytywna ", 1)); 19 łapacz1.łapŻądanie(new Żądanie("Wartość negatywna ", -1)); 20 } 21 } 22
Diagram wzorca:


September 29th, 2009 at 14:41
Przy ostatnim projekcie uprościłem także klasę abstrakcyjną w setterze dla następnego Handlera. Otóż dodałem kod sprawdzający, czy Handler już istnieje i w przypadku gdy istnieje deleguję dodanie handlera do obecnego. Trochę to upraszcza sprawę, ponieważ, dodając do obojętnie którego Handlera następcę, ten ląduje na końcu kolejki. W przypadku, gdy kolejność jest nam obojętna jest dużym ułatwieniem.
September 29th, 2009 at 14:47
Przyglądając się powyżej opisanemu wzorcowi, można zauważyć, że nie jest do końca zachowana zasada DRY. W każdym handlerze jest warunek sprawdzania, czy kolejny handler istnieje, a w przypadku gdy istnieje, metoda przechodzi dalej. Można to trochę ułatwić, przenosząc ten kod do abstrakcyjnej metody np. o nazwie ‘next(); metoda ‘łapŻądanie(), stanie się bardziej przejżysta, a w metodzie next() najpierw wywołamy łapŻądanie() a potem będzie kod sprawdzający. Pamiętać należy, żeby uruchomić łańcuch przez nową metodę.