2009-06-04 5 views
8

Cette question est une sorte de continuation à mon poste précédent: Visitor pattern implementation in java- How does this look?Modèle de stratégie composite - Java - Quelle est la gravité de ce code?

Je me suis un peu perdu en refacturant mon code. J'essaye de convertir mon modèle de visiteur (expliqué dans la publication précédente) dans un modèle de stratégie composé. Je suis en train de faire quelque chose comme ceci:

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

Maintenant, je définirais une règle comme ceci:

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. 
    } 
} 

Maintenant, je pourrais avoir deux objets différents types à valider. Ces deux pourraient être complètement différents: Dites que j'ai un magasin qui est Validatable, puis un Schedule qui est Validatable. Maintenant, si j'écrirais un composite qui ressemblerait à ceci:

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(); 
    } 
} 

Je définirais un enum qui définit un ensemble de contrôles où aller ...

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 
} 

et enfin, je voudrais utiliser comme ceci:

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

J'ai un étrange sentiment que mon design est défectueux. Je n'aime pas l'idée que mon interface de règle attend un Validatable. Pourriez-vous me suggérer comment je pourrais améliorer cela?

Appréciez votre aide.

+0

Vous enfreignez toutes les règles de l'indentation. Si vous voulez que les autres regardent et vous aident avec quelque chose que votre code doit regarder un peu mieux.En ce moment, il a une horrible odeur de code. –

+0

@Trevor Désolé à ce sujet, réparé maintenant. – Jay

+0

L'indentation était encore un peu illisible. Je l'ai corrigé. – Eddie

Répondre

4

Remplacer Valide par un paramètre de type générique T pour sécuriser le type de structure de validation.

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

étendons notre cadre avec une interface ValidationStrategy:

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

Nous avons affaire à des règles bornées par afin que nous puissions ajouter une règle pour les animaux à un chien Validator (en supposant chien « super T? » étend Animal). Le validateur ressemble maintenant à ceci:

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; 
    } 
} 

Maintenant, nous pouvons mettre en œuvre un échantillon DogValidationStrategy comme ceci:

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; 
    } 
} 

Ou, comme dans votre exemple, nous pouvons avoir un Enum fournissant plusieurs stratégies de validation de chien:

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

@chris Merci, votre réponse aide. J'ai une question. Dans Dog ValidationStrategy, je voudrais? étend Animal non? super-chien. Cela garantirait qu'une seule règle peut être appliquée à Dog et Cat. Maintenant, quand j'essaye de déclarer tout comme T étend Animal, le compilateur se plaint de la boucle for dans la classe Validator. Je reçois ce message d'erreur: La méthode check (capture-of? Extends Animal) dans le type Rule n'est pas applicable pour les arguments (T) – Jay

+0

@chris votre réponse est la plus proche de ce que je veux, si vous pouvez répondre à mon commentaire, j'accepterai votre réponse. – Jay

+0

Jay, si une règle est destinée à être appliquée aux chiens * et * aux chats, cela ne devrait-il pas être une règle animale? Si vous pouvez faire ce que vous avez décrit, une règle de chat peut être passée dans un chien en échec (animal). – chris

9

Quand j'ai découvert les motifs de design pour la première fois, j'ai continué à essayer de trouver des endroits pour les utiliser. J'ai appris depuis que la «patternisation» prématurée est un peu comme une optimisation prématurée. D'abord, essayez de le faire d'une manière directe, puis voyez les problèmes que cela vous pose. Essayez de concevoir avec un minimum d'interfaces et de sous-classes. Ensuite, appliquez n'importe quel modèle approprié pour les redondances évidentes que vous trouvez. J'ai l'impression de ceci et le post précédent que vous pourriez sur-architecturer votre code.

+0

@Jeremy Qu'est-ce qui ne va pas avec l'exemple de code dans le post ci-dessus? – Jay

+1

Et si vous venez d'écrire: pour (Store store: stores) { validate_store (store); } À un moment donné, vous devrez définir quelle validation est effectuée sur quels types. Comment coder dur est-il bien pire que d'ajouter toute cette complexité à votre code et de l'extérioriser ensuite? Avant de critiquer le code lui-même, je remets en question la situation dans son ensemble. –

+0

@Jeremy: Cela ressemble à faire deux fois le même travail. Je vous recommande de consulter la boîte à outils TTP à http://ttp.essex.ac.uk/ Aussi, chaque fois que je vois un motif, je l'utilise. J'utilise mon expérience passée pour résoudre des problèmes. Je me réfère également à l'UML pour voir si je peux refactoriser le design avant de coder. Cela économise du temps, le temps c'est de l'argent. –

Questions connexes