2009-06-04 7 views
8

Diese Frage ist eine Art Fortsetzung zu meinem früheren Beitrag: Visitor pattern implementation in java- How does this look?Zusammengesetzte Strategie Muster - Java - Wie schlimm ist dieser Code?

Ich habe ein wenig verwirrt, während ich meinen Code refactoring. Ich versuche, mein Besuchermuster (das im vorherigen Post erklärt wurde) in ein zusammengesetztes Strategie-Muster umzuwandeln. Ich versuche, so etwas zu tun:

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

Jetzt habe ich eine Regel wie folgt definieren würde:

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

Nun, ich zwei verschiedene Arten haben könnten Objekte validiert werden. Diese zwei könnten völlig unterschiedlich sein: Angenommen, ich habe einen Store, der Validatable ist, und dann einen Schedule, der Validatable ist. Nun, wenn ich einen Verbund schreiben würde, die wie folgt aussehen:

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

Ich würde definieren eine enum das, was Reihe von Kontrollen definiert gehen, wo ...

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 
} 

und schließlich würde ich es ist wie folgt:

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

Ich habe ein seltsames Gefühl, dass mein Design fehlerhaft ist. Mir gefällt die Idee nicht, dass meine Regelschnittstelle eine Validatable erwartet. Könnten Sie mir bitte vorschlagen, wie ich das verbessern würde?

Schätzen Sie Ihre Hilfe.

+0

Sie brechen alle Regeln der Vertiefung. Wenn Sie möchten, dass andere etwas sehen und Ihnen bei etwas helfen, muss Ihr Code etwas besser aussehen.Gerade jetzt hat es schrecklichen Code Geruch. –

+0

@Trevor Entschuldigung, habe es jetzt behoben. – Jay

+0

Der Eindruck war immer noch etwas unlesbar. Ich habe es repariert. – Eddie

Antwort

4

ersetzen Validierbares durch einen generischen Typparameter T die Validation Framework Art sicher zu machen.

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

wir unseren Rahmen mit einer Schnittstelle ValidationStrategy erweitern:

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

Wir beschäftigen uns mit Regeln begrenzt durch, damit wir eine Regel für Tier an einen Hund Validator hinzufügen (unter der Annahme Dog „Super T?“ verlängert Tier). Der Validator sieht nun wie folgt aus:

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

Jetzt können wir eine Probe DogValidationStrategy wie folgt implementieren:

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

Oder wie in der Probe, können wir eine Enum bietet mehrere Hund Validierungsstrategien haben:

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

@chris Danke, deine Antwort hilft. Ich habe eine Frage. In Dog ValidationStrategy möchte ich? verlängert Tier nicht? super Hund. Dies würde sicherstellen, dass eine einzige Regel auf Hund und Katze angewendet werden kann. Wenn ich jetzt versuche, alles so zu erklären, dass T Tier ausdehnt, beschwert sich der Compiler über die for-Schleife in der Validator-Klasse. Ich bekomme diese Fehlermeldung: Die Methode check (capture-of? Erweitert Animal) im Typ Regel ist nicht anwendbar für die Argumente (T) – Jay

+0

@chris Ihre Antwort ist am nächsten, was ich will, wenn Sie meinen Kommentar beantworten können, werde ich Ihre Antwort akzeptieren. – Jay

+0

Jay, sollte eine Regel für Hunde * und * Katzen gelten, sollte das nicht eine Tierregel sein? Wenn Sie das tun könnten, was Sie beschrieben haben, kann eine Katzenregel in einem Hund im Scheck (Tier) übergeben werden. – chris

9

Als ich erfuhr, über Design Patterns ersten, hielt ich versuche, Orte zu finden, sie zu nutzen. Ich habe inzwischen gelernt, dass vorzeitige "Musterbildung" ist wie eine vorzeitige Optimierung. Versuchen Sie zuerst, es auf eine geradlinige Weise zu tun, und dann sehen Sie, welche Probleme Sie gibt.

Versuchen mit minimalen Schnittstellen und Subklassen zu entwerfen. Wenden Sie dann das Muster an, das für die offensichtlichen Redundanzen, die Sie finden, geeignet sein könnte. Ich habe den Eindruck von diesem und dem vorherigen Beitrag, dass Sie Ihren Code möglicherweise überarbeiten.

+0

@ Jeremy Was ist insbesondere falsch mit dem Codebeispiel im obigen Beitrag? – Jay

+1

Was, wenn Sie gerade geschrieben haben: für (Geschäft speichern: Geschäfte) { validate_store (speichern); } Irgendwann müssen Sie definieren, welche Validierung für welche Typen durchgeführt wird. Wie schwer ist es, es so viel schlechter zu kodieren, als all diese Komplexität in den Code zu integrieren und dann zu externalisieren? Bevor ich auf den Code selbst nicke, hinterfrage ich das große Bild. –

+0

@ Jeremy: Das klingt wie zweimal die gleiche Arbeit zu tun. Ich empfehle Ihnen, sich das TTP Toolkit unter http://ttp.essex.ac.uk/ anzuschauen. Wenn ich ein Muster sehe, benutze ich es auch. Ich nutze meine Erfahrung in der Vergangenheit, um Probleme zu lösen. Ich beziehe mich auch auf die UML, um zu sehen, ob ich das Design vor dem Code umgestalten kann. Das spart Zeit, Zeit ist Geld. –