2009-06-04 11 views
8

Esta pregunta es una especie de continuación de mi publicación anterior: Visitor pattern implementation in java- How does this look?Patrón de estrategia compuesta - java - ¿Qué tan malo es este código?

Me confundí un poco al refacturar mi código. Estoy tratando de convertir mi patrón de visitante (explicado en la publicación anterior) en un patrón de estrategia compuesto. Estoy tratando de hacer algo como esto:

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

Ahora, me gustaría definir una regla como la siguiente:

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

Ahora, podría haber dos tipos diferentes objetos para ser validado. Estos dos podrían ser completamente diferentes: Supongamos que tengo una tienda que es Validatable, y luego una Schedule que es Validatable. Ahora, si me gustaría escribir un compuesto que se vería así:

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

Yo definiría un enum que define qué conjunto de controles de ir a donde ...

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 
} 

y, por último, me gustaría utilizar es así:

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

Tengo la extraña sensación de que mi diseño es defectuoso. No me gusta la idea de que mi interfaz de reglas espere un Validatable. ¿Podría sugerirme cómo mejoraría esto?

Agradecemos su ayuda.

+0

Estás rompiendo todas las reglas de indentación. Si desea que los demás lo miren y lo ayuden con algo, su código debe verse un poco mejor.En este momento tiene un código horrible. –

+0

@Trevor Perdón por eso, lo arreglé ahora. – Jay

+0

La sangría todavía era algo ilegible. Lo arreglé. – Eddie

Respuesta

4

Reemplazar Validables por un parámetro de tipo genérico T para hacer que el tipo de marco de validación sea seguro.

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

extendamos nuestro marco con una interfaz ValidationStrategy:

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

Se trata de reglas delimitadas por lo que podemos añadir una regla para el animal a un validador de perro (suponiendo perro "Super T?" extiende Animal). El Validador ahora se ve así:

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

Ahora podemos implementar un DogValidationStrategy muestra de la siguiente manera:

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

O, al igual que en la muestra, que puede tener una enumeración que proporciona varias estrategias de validación perro:

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

@ chris Gracias, tu respuesta ayuda. Tengo una pregunta. En Dog ValidationStrategy, me gustaría? extiende Animal no? súper perro. Esto garantizaría que se pueda aplicar una sola regla a perros y gatos. Ahora, cuando trato de declarar todo cuando T se extiende Animal, el compilador se queja del bucle for en la clase Validator. Aparece este mensaje de error: La comprobación del método (captura-de? Extiende Animal) en el tipo Regla no es aplicable para los argumentos (T) – Jay

+0

@chris tu respuesta es la más cercana a la que deseo, si puedes responder mi comentario, aceptaré tu respuesta. – Jay

+0

Jay, si una regla se aplica a perros * y * gatos, ¿no debería ser una regla animal? Si pudieras hacer lo que describes, se puede pasar una regla de gato en un perro bajo control (animal). – chris

9

Cuando me enteré de los patrones de diseño, seguí intentando encontrar lugares para usarlos. Desde entonces, aprendí que la "pautarización" prematura es como una optimización prematura. Primero, intente hacerlo de una manera directa, y luego vea qué problemas le da.

Intente diseñar con interfaces y subclases mínimos. Luego aplique cualquier patrón que sea apropiado para las redundancias obvias que encuentre. Me da la impresión de esta y la publicación anterior de que puede que esté sobre-diseñando su código.

+0

@Jeremy ¿qué es lo que está mal con el ejemplo de código en la publicación anterior? – Jay

+1

¿Qué pasa si acaba de escribir: for (Store store: stores) { validate_store (store); } En algún momento, tendrá que definir qué validación se realiza en qué tipos. ¿Cómo es difícil codificarlo mucho peor que agregar toda esta complejidad a su código y luego externalizarlo? Antes de señalar el código en sí, estoy cuestionando el panorama general. –

+0

@Jeremy: Esto suena como hacer el mismo trabajo dos veces. Te recomiendo que veas el TTP Toolkit en http://ttp.essex.ac.uk/ Además, cada vez que veo un patrón, lo uso. Uso mi experiencia pasada para resolver problemas. También me refiero al UML para ver si puedo refactorizar el diseño antes de codificar. Esto ahorra tiempo, el tiempo es dinero. –

Cuestiones relacionadas