2009-06-04 10 views
8

questa domanda è sorta di continuazione al mio post precedente: Visitor pattern implementation in java- How does this look?Pattern di strategia composita - java - Quanto è pericoloso questo codice?

mi sono un po 'confuso, mentre il refactoring il mio codice. Sto cercando di convertire il mio modello di visitatore (spiegato nel post precedente) in un modello di strategia composita. Sto cercando di fare qualcosa di simile:

public interface Rule { 
    public List<ValidatonError> check(Validatable validatable); 
} 

Ora, vorrei definire una regola come questa:

public class ValidCountryRule { 
    public List<ValidationError> check(Validatable validatable) { 
    // invokeDAO and do something, if violation met 
    // add to a list of ValidationErrors. 
    // return the list. 
    } 
} 

Ora, potrei avere due tipi diversi oggetti da convalidare. Questi due potrebbero essere completamente diversi: dire che ho un negozio che è Validatable, e quindi un Schedule che è Validatable. Ora, se io avrei scritto un composito che sarebbe simile a questa:

class Validator implements Rule { 
    private List<Rule> tests = new ArrayList<Rule>(); 

    public void addRule(Rule rule) { 
    tests.add(rule); 
    } 

    public List<ValidationError> check(Visitable visitable) { 
    List<ValidationError> list = new ArrayList<ValidationError>(); 
    for(Rule rule : tests) { 
     list.addAll(rule.check(visitable); 
    } 
    } 

    public Validator(ValidatorType type) { 
    this.tests = type.getRules(); 
    } 
} 

vorrei definire un enum che definisce un insieme di controlli andare dove ...

public Enum ValidatorType { 
    public abstract List<Rule> getRules(); 
    STORE_VALIDATOR { 
    public List<Rule> getRules() { 
     List<Rule> rules = new ArrayList<Rule>(); 
     rules.add(new ValidCountryRule()); 
     rules.add(new ValidXYZRule()); 
    } 

    // more validators 
} 

e, infine, vorrei utilizzare così:

Validator validator = new Validator(ValidatorType.STORE_VALIDATOR); 
for (Store store : stores) { 
    validator.check(store); 
} 

Ho la strana sensazione che il mio disegno sia difettoso. Non mi piace l'idea che la mia interfaccia Rule si aspetta un Validatable. Potresti per favore suggerire come migliorerei questo?

Apprezzo il tuo aiuto.

+0

Stai rompendo tutte le regole di indentazione. Se vuoi che gli altri guardino e ti aiutino con qualcosa il tuo codice ha bisogno di apparire un po 'meglio.In questo momento ha un odore di codice orribile. –

+0

@Trevor Ci scusiamo, l'ho risolto ora. – Jay

+0

La rientranza era ancora alquanto illeggibile. L'ho riparato. – Eddie

risposta

4

Sostituisci Validabile con un parametro di tipo generico T per rendere sicuro il tipo di framework di convalida.

public interface Rule<T> { 
    public List<ValidationError> check(T value); 
} 

Diamo estendere il nostro quadro con un'interfaccia ValidationStrategy:

public interface ValidationStrategy<T> { 
    public List<Rule<? super T>> getRules(); 
} 

Abbiamo a che fare con le regole delimitate da in modo che possiamo aggiungere una regola per Animal ad un validatore Dog (assumendo Dog "super-T?" estende l'animale). Il Validator ora assomiglia a questo:

public class Validator<T> implements Rule<T> { 
    private List<Rule<? super T>> tests = new ArrayList<Rule<? super T>>(); 

    public Validator(ValidationStrategy<T> type) { 
     this.tests = type.getRules(); 
    } 

    public void addRule(Rule<? super T> rule) { 
     tests.add(rule); 
    } 

    public List<ValidationError> check(T value) { 
     List<ValidationError> list = new ArrayList<ValidationError>(); 
     for (Rule<? super T> rule : tests) { 
      list.addAll(rule.check(value)); 
     } 
     return list; 
    } 
} 

Ora possiamo implementare una DogValidationStrategy campione come questo:

public class DogValidationStrategy implements ValidationStrategy<Dog> { 
    public List<Rule<? super Dog>> getRules() { 
     List<Rule<? super Dog>> rules = new ArrayList<Rule<? super Dog>>(); 
     rules.add(new Rule<Dog>() { 
      public List<ValidationError> check(Dog dog) { 
       // dog check... 
       return Collections.emptyList(); 
      } 
     }); 
     rules.add(new Rule<Animal>() { 
      public List<ValidationError> check(Animal animal) { 
       // animal check... 
       return Collections.emptyList(); 
      } 
     }); 
     return rules; 
    } 
} 

Oppure, come nel tuo esempio, possiamo avere un Enum che fornisce diverse strategie di validazione cane:

public enum DogValidationType implements ValidationStrategy<Dog> { 
    STRATEGY_1 { 
     public List<Rule<? super Dog>> getRules() { 
      // answer rules... 
     } 
    }, 
    // more dog validation strategies 
} 
+0

@chris Grazie, la tua risposta ti aiuta. Ho una domanda. In Dog ValidationStrategy, vorrei? non estende l'animale? super cane. Ciò garantirebbe che una singola regola possa essere applicata a Cane e Gatto. Ora, quando provo a dichiarare tutto come T estende Animal, il compilatore si lamenta del ciclo for nella classe Validator. Ricevo questo messaggio di errore: Il controllo del metodo (capture-of? Extends Animal) nel tipo Rule non è applicabile per gli argomenti (T) – Jay

+0

@chris la tua risposta è la più vicina a quello che voglio, se puoi rispondere al mio commento, accetterò la tua risposta. – Jay

+0

Jay, se una regola deve essere applicata ai cani * e * gatti, non dovrebbe essere una regola animale? Se potessi fare ciò che hai descritto, una regola di gatto può essere passata in un cane sotto controllo (animale). – chris

9

Quando ho appreso per la prima volta degli schemi di progettazione, ho continuato a cercare luoghi per utilizzarli. Da allora ho imparato che la "modellizzazione" prematura è un po 'come l'ottimizzazione prematura. Per prima cosa, prova a farlo in modo diretto e poi vedi quali problemi ti danno.

Provare a progettare con interfacce e sottoclassi minime. Quindi applica qualsiasi modello appropriato per le ridondanze evidenti che trovi. Ho l'impressione da questo e dal post precedente che potresti essere sopra-architettando il tuo codice.

+0

@Jeremy cosa in particolare è sbagliato con il codice di esempio nel post sopra? – Jay

+1

Cosa succede se hai appena scritto: per (Negozio: negozi) { validate_store (store); } A un certo punto è necessario definire quale convalida viene eseguita su quali tipi. In che modo l'hard-coding è così peggio che aggiungere tutta questa complessità al codice e quindi esternalizzarlo? Prima di azzerare il codice stesso, sto mettendo in discussione il quadro generale. –

+0

@Jeremy: Sembra fare lo stesso lavoro due volte. Ti consiglio di dare un'occhiata al TTP Toolkit all'indirizzo http://ttp.essex.ac.uk/ Inoltre, ogni volta che vedo uno schema lo uso. Uso la mia esperienza passata per risolvere i problemi. Mi riferisco anche a UML per vedere se riesco a rifattorizzare il disegno prima di codificare. Ciò consente di risparmiare tempo, il tempo è denaro. –