venerdì 28 novembre 2008

Chain-Of-Responsability Design Pattern

CHAIN-OF-RESPONSABILITY DESIGN PATTERN:

Obiettivo: fare in modo che una richiesta possa essere processata da uno di più oggetti. Tale richiesta passa per una catena di oggetti finchè uno di essi non la gestisce.

Il può noto esempio di applicazione di questo design pattern è la gestione delle eccezioni in java. Quando durante l'esecuzione del metodo di una classe scatta un'eccezione, la classe può gestirela (tramite il meccanismo try-catch) o delegarne la responsabilità della gestione alla classe che ha invocato il metodo(tramite il costrutto throws). Quest'ultima classe può gestirla o a sua volta sollevare l'eccezione alla classe da cui è stata invocata. Un altro esempio di utilizzo di questo design pattern è quello dell'utilizzo della classe javax.servlet.Filter in un'applicazione web. Il metodo chain.doFilter() viene richiamato per fare in modo che tutti i filtri di una servlet possano processare una richiesta prima che essa venga processata dalla stessa servlet. Se un solo filtro della catena blocca la richiesta allora la richiesta viene 'annullata' dal web container.

Nel nostro esempio useremo il design pattern Chain of Responsability per creare una semplice applicazione (a scopo puramente didattico) che determina se una data nel formato ("yyyy" "mm" "dd") è corretta. I requisiti di correttezza sono che
  • "yyyy" "mm" "dd" rappresentino interi,
  • 1<=mm>=12
  • 1<=dd>=31, 1<=dd>=30  per i mesi aprile, giugno, settembre e novembre, 1<=dd>=29 se mm=02 negli anni bisestili, 1<=dd>=28 se mm=02 negli anni non bisestili

Nel seguente listato tali controlli vengono affidati ad una catena di oggetti, ognuno dei quali verifica che sia verificato un requisito specifico. Se uno solo di tali oggetti rivela che la data non è correttamente definita è inutile continuare nei controlli.


package designPatterns.chainofresponsability;

public class Main {
    public static void main(String[] args) {
        MyDate myDate = new MyDate("1981", "13", "6");
        IsNumericFilter isNumericFilter = new IsNumericFilter();
        MonthFilter monthFilter = new MonthFilter();
        DayFilter dayFilter = new DayFilter();
        isNumericFilter.doChain(monthFilter);
        monthFilter.doChain(dayFilter); 
        isNumericFilter.doFilter(myDate);
    }
}

class MyDate{
    private String year;
    private String month;
    private String day;
    public MyDate(String y, String m, String d) {
        this.year = y;
        this.month = m;
        this.day = d;
    }
    public String getDay() {
        return day;
    }
    public String getMonth() {
        return month;
    }
    public String getYear() {
        return year;
    }
}

abstract class MyDateFilter{
    protected MyDateFilter successorMyDateFilter;
    protected String wrongDate = "Data non corretta";
    protected String okDate = "Data corretta!!";
    public void doChain(MyDateFilter successor){
        this.successorMyDateFilter=successor;
    }
    public abstract void doFilter(MyDate myDate);
}

class IsNumericFilter extends MyDateFilter{
    @Override
    public void doFilter(MyDate myDate) {
        if(!isNumeric(myDate.getYear()) ||
                !isNumeric(myDate.getMonth()) ||   
                !isNumeric(myDate.getDay()))
            System.out.println(wrongDate);
        else
            successorMyDateFilter.doFilter(myDate);
       
    }
    private boolean isNumeric(String param){
        try{
            Integer.parseInt(param);
        }catch(NumberFormatException e){
            return false;
        }
        return true;
    }
}

class MonthFilter extends MyDateFilter{
    @Override
    public void doFilter(MyDate myDate) {
        String mString = myDate.getMonth();
        int month = Integer.parseInt(mString);
        if(month<1 || month>12)
            System.out.println(wrongDate);
        else
            successorMyDateFilter.doFilter(myDate);
    }
}

class DayFilter extends MyDateFilter{
    @Override
    public void doFilter(MyDate myDate) {
        String dString = myDate.getDay();
        String mString = myDate.getMonth();
        String yString = myDate.getYear();
        int year = Integer.parseInt(yString);
        int day = Integer.parseInt(dString);
        if(day<1 || day>31)
            System.out.println(wrongDate);
        else if(isShortMonth(mString) && dString.equals("31"))           
            System.out.println(wrongDate);
        else if(mString.equals("2")){
            if(new java.util.GregorianCalendar().isLeapYear(year)){
                if(day>29)
                     System.out.println(wrongDate);
            }else if(day>28)
                 System.out.println(wrongDate);
        }
          
        else
            System.out.println(okDate);
    }
    private boolean isShortMonth(String mString){
        int month = Integer.parseInt(mString);
        if(month==4 || month==6 || month==9 || month==11)
            return true;
        return false;
    }
}


Nessun commento: