문제

Alrite, 나는 코드로 바로 점프 할 것이다 :

public interface Visitor {

public void visitInventory(); 
public void visitMaxCount();
public void visitCountry();
public void visitSomethingElse();
public void complete();
//the idea of this visitor is that when a validator would visit it, it would validate data
//when a persister visits it, it would persist data, etc, etc.
// not sure if I making sense here...
}

public interface Visitable {
public void accept(Visitor visitor); 
}

기본 구현은 다음과 같습니다.

public class StoreValidator implements Visitor {
private List <ValidationError> storeValidationErrors = new ArrayList<ValidationError>();

public void addError(ValidationError error) {
storeValidationErrors.add(error);
}

public List<ValidationError> getErrors() {
return storeValidationErrors;
}

public void visitInventory() {
// do nothing 
}

public void visitMaxCount() {
//do nothing
}
//... etc..  all empty implementations 

}

내가 왜 빈 구현을했는지 알 수있을 것입니다 ... 지금 유효성 검사기를 쓸 것입니다.

public XYZValidator extends StoreValidator {

@Override 
public void visitInventory(Visitable visitable) { 
// do something with visitable .. cast it to expected type
// invoke a DAO, obtain results from DB
// if errors found, do addError(new ValidationError()); with msg.
}

@Override 
public void visitMaxCount(Visitable visitable) {
//do something with visitable.. 
}

// I wouldn't implement the rest coz they wouldn't make sense
// in XYZValidator.. so they are defined as empty in StoreValidator.

}

이제 방문 가능한 모습은 다음과 같습니다.

public Store implements Visitable {

public void accept(Visitor visitor) {
visitor.visitInventory();
visitor.visitMaxCount();
}
}

상점 개체 목록에 이와 같은 작업을 수행하는 코드를 가질 수 있습니다.

List<Store> stores; //assume this has a list of stores.
StoreValidator validator = new XYZValidator(); //or I would get it from a validatorfactory
for(Store store: stores) {
           store.accept(validator); // so even if you send a wrong validator, you are good.
}

마찬가지로 다른 방법 (Visitcountry / Visitomethinelse)에 대한 구현을 제공하는 abcvalidator가있을 것이며 StoreValidator에서 확장됩니다. 수락 방법을 정의하는 다른 유형의 객체 (저장 아님)가 있습니다.

여기에 문제가 있습니다 ... storevalidator와 다른 FileValidator가 필요합니다. VisitinVentory () 등과 같은 비즈니스 관련 유효성 검사가 없을 것으로 예상됩니다. 방문자 인터페이스에서 모든 종류의 방법을 선언했습니다. 그 맞습니까? 이것이 당신이하는 방법입니까?

패턴이 잘못되었는지 또는 이해가 될지 모르겠습니다. 당신의 생각을 공유하십시오.

도움이 되었습니까?

해결책

주어진 코드에 문제가 있습니다. 당신이 제공하는 인터페이스에는 다음과 같은 방법이 있습니다

public void visitInventory(); 

그러나 xyzvalidator에서 AS를 구현합니다

public void visitInventory(Visitable visitable)

그만큼 방문자 패턴 구현하는 방법입니다 다중 발송 자동으로 수행하지 않는 언어 (예 : Java). 요구 사항 중 하나는 관련 클래스 그룹이 있어야합니다 (예 : 단일 슈퍼 클래스가있는 하위 클래스 세트). 여기에 그 점이 없으므로 방문자 패턴이 적절하지 않습니다. 그러나 당신이하려는 과제는 괜찮습니다. 그것은 단지 방문자 패턴이 아닙니다.

Java에서는 코드가있는 경우 방문자 패턴을 생각해야합니다.

public void count(Item item) {
  if (item instanceof SimpleItem) {
    // do something
  } else if (item instanceof ComplexItem {
    // do something else
  } else ...
}

특히 항목의 서브 클래스가 비교적 고정 된 경우.

다른 팁

얼마 전에 나는 마스터 논문과 비슷한 것을 썼습니다. 이 코드는 귀하보다 약간 안전합니다.

interface Visitable<T extends Visitor> {

   void acceptVisitor(T visitor);
}

interface Visitor {

    /**
     * Called before any other visiting method.
     */
    void startVisit();

    /**
     * Called at the end of the visit. 
     */
    void endVisit();
}

예시:

interface ConstantPoolVisitor extends Visitor {

    void visitUTF8(int index, String utf8);

    void visitClass(int index, int utf8Index);

    // ==cut==
}

class ConstantPool implements Visitable<ConstantPoolVisitor> {

    @Override
    public void acceptVisitor(ConstantPoolVisitor visitor) {
        visitor.startVisit();

        for (ConstanPoolEntry entry : entries) {
            entry.acceptVisitor(visitor);
        }

        visitor.endVisit();
    }

그렇습니다. 데이터가 동작보다 느리게 변경되는 경우에만 이것이 좋고 유연한 디자인이라고 생각합니다. 내 예에서는 데이터가 Java Bytecode이며, 이는 고정 된 (JVM 사양에 의해 정의 됨). "동작이 지배적 인"경우 (내 바이트 코드를 덤프, 컴파일, 변환, 리팩터 등) 방문자 패턴을 사용하면 데이터 클래스를 만지지 않고 동작을 변경/추가/제거 할 수 있습니다. 방문자의 다른 구현 만 추가하십시오.

단순성을 위해 방문자 인터페이스에 또 다른 방문 방법을 추가해야한다고 가정합니다. 모든 코드를 깨뜨릴 것입니다.

대안 으로이 시나리오의 전략 패턴을 고려할 것입니다.. 전략 + 데코레이터는 검증을위한 좋은 디자인입니다.

나는 다른 방식으로 방문자 패턴을 사용하고 있습니다. 나는 객체 유형에 대한 특정 방문자 인터페이스가 있으며이 인터페이스는 그 개체를 방문하기위한 하나의 방법 만 선언합니다.

public interface TreeNodeVisitor {
    void visit(TreeNode node);
}

그 물체 트린 노드 수락 할 수 있습니다 TreenodevisitorS는 그가 단지 그것을 부르는 것을 의미합니다 방문 노드 및/또는 어린이를위한 방법 ..

방문자의 구체적인 구현은 방문 방법과 방문자가 할 일을 말합니다. 예를 들어 Contryvisitor, Inventoryvisitor 등

이 접근법은 귀하의 문제를 피해야합니다 ..

아마도 패턴을 한 단일 인터페이스에 직접 매핑하고 싶지 않을 것입니다. 패턴은 인터페이스가 아니며 솔루션을 구현하기위한 일반적인 계획입니다.

예에서는 적절한 상황에서 방문자 패턴을 사용하려는 다른 비즈니스 객체에 대한 Storevisitor 인터페이스와 FileVisitor 인터페이스를 만듭니다.

다른 방문자 구현은 공통 활동을 공유 할 수 있으므로 이러한 공통 기능을 정의하는 슈퍼 interface를 가질 수 있습니다. 그런 다음 방문 가능한 인터페이스를 코딩하여 특정 방문 가능한 인터페이스 또는 적절한 수퍼 클래스를 사용할 수 있습니다.

예를 들어, FileVisitor 및 SQLTableVisitor 인터페이스는 DataStoreVisitor 인터페이스의 서브 클래스 일 수 있습니다. 그 다음에:

VisitableStore는 Storvisitor를 수락합니다.

VisitableFile은 FileVisitor를 수락합니다

visitabledatatastore는 DataStoreVistor (FileVisitor 또는 SQLTableVisitor의 구현 일 수 있음)를 수락합니다.

  • 임의의 예를 용서하십시오. 이것이 의미가 있기를 바랍니다.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top