2009-06-04 8 views
8

이 질문은 이전 게시물의 일부입니다. Visitor pattern implementation in java- How does this look?복합 전략 패턴 - java -이 코드는 얼마나 나쁜가요?

내 코드를 리팩터링하는 동안 약간 혼란스러워졌습니다. 이전 방문에서 설명한 방문자 패턴을 복합 전략 패턴으로 변환하려고합니다. 나는 이런 식으로 뭔가를 시도하고있다 : 이제

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

, 나는 다음과 같은 규칙을 정의 할 :

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

을 지금, 나는이 두 가지 유형을 가질 수 것은 검증 될 객체. 이 두 가지는 완전히 다른 것일 수 있습니다. Validatable 인 상점과 인 Schedule이 있다고 가정 해보십시오. 나는이 같을 것이다 복합을 작성하면 이제 :

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

나는 ... 검사의 설정 무엇을 정의하는 enum가 어디로 가야

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 
} 

을 정의하는 것 그리고 마지막으로, 내가 사용하는 것이 그것은 다음과 같습니다 :

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

나는 내 디자인에 결함이 있다는 이상한 느낌이 있습니다. 내 Rule 인터페이스가 Validatable을 기대하고 있다는 생각을 좋아하지 않습니다. 이걸 어떻게 향상 시킬지 제안 해 주시겠습니까?

감사합니다.

+0

들여 쓰기의 모든 규칙을 위반했습니다. 다른 사람들이보고 바라는 것을 원한다면 코드가 좀 더 잘 보이도록해야합니다.지금은 끔찍한 코드 냄새가 난다. –

+0

@ Trevor 죄송합니다. 지금 고쳐 주셨습니다. – Jay

+0

들여 쓰기는 여전히 다소 읽을 수 없었습니다. 나는 그것을 고쳤다. – Eddie

답변

4

유효성 검사 프레임 워크 형식을 안전하게 만들기 위해 Validatable를 일반 형식 매개 변수 T로 바꿉니다.

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

을 우리는 그래서 우리는 (개 가정 개가 검사기에 동물에 대한 규칙을 추가 할 수 있습니다에 의해 제한 규칙을 다루고있는 '슈퍼 T? "

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

의가 인터페이스 ValidationStrategy 우리의 프레임 워크를 확장 할 수

Animal을 확장). 유효성 검사기는 이제 다음과 같습니다 여러 개 검증 전략을 제공하는 열거를

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

또는 샘플처럼, 우리는 할 수 있습니다 :

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

이제 우리는이 같은 샘플 DogValidationStrategy을 구현할 수 있습니다

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

@chris 감사합니다. 답변이 도움이됩니다. 질문이 하나 있습니다. Dog ValidationStrategy에서 내가 원했던가? 동물을 연장하지 않습니까? 슈퍼 개. 이렇게하면 Dog와 Cat에 단일 규칙을 적용 할 수 있습니다. 이제 T가 Animal을 확장 할 때 모든 것을 선언하려고하면 컴파일러는 Validator 클래스의 for 루프에 대해 불평합니다. 이 오류 메시지가 나타납니다 : 규칙 은 인수에 적용되지 않습니다 (T) – Jay

+0

@chris 내 대답에 가장 가까운 답변입니다. 내 의견에 답할 수 있으면 답변을 수락합니다. – Jay

+0

Jay, 규칙이 개 *와 * 고양이에 적용될 예정이라면, 동물 규칙이되어서는 안됩니까? 당신이 묘사 한 것을 할 수 있다면, 고양이 규칙은 수표 (동물)의 개를 통과 할 수 있습니다. – chris

9

처음 디자인 패턴에 대해 배울 때, 나는 계속 사용할 패턴을 찾고있었습니다. 나는 조숙 한 "패턴 화"가 조숙 한 최적화와 같다고 배웠습니다. 먼저, 그것을 직선적 인 방식으로 시도한 다음, 어떤 문제가 발생했는지 확인하십시오.

최소한의 인터페이스와 하위 클래스로 디자인 해보십시오. 그런 다음 분명한 중복을 위해 적절한 패턴을 적용하십시오. 이 코드와 이전 게시물에서 여러분이 코드를 너무 많이 만들었다는 인상을받습니다.

+0

@Jeremy 특히 위 게시물의 코드 샘플에 어떤 문제가 있습니까? – Jay

+1

방금 ​​쓴 경우 : (점포 스토어 : 점포) { validate_store (store); } 어떤 시점에서 어떤 유형의 검증이 수행되어야하는지 정의해야합니다. 이 모든 복잡성을 코드에 추가 한 다음이를 외부화하는 것보다 코드를 너무 많이 코딩하는 것이 어떻습니까? 코드 자체를 질질 끌기 전에 큰 그림을 묻습니다. –

+0

@ 제레미 : 같은 일을 두 번하는 것처럼 들립니다. http://ttp.essex.ac.uk/ 에서 TTP 툴킷을 살펴 보는 것도 좋습니다. 또한 패턴을 볼 때마다 사용합니다. 나는 과거 경험을 사용하여 문제를 해결합니다. 또한 코드를 작성하기 전에 UML을 참조하여 디자인을 리팩터링 할 수 있는지 확인합니다. 이것은 시간을 절약하고 시간은 돈입니다. –