방문자가 방문객 패턴에서 어린이를 열거하는 책임이있는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/522803

문제

내가 찾은 코드를 바탕으로 방문자는 방문한 물체의 구조를 알고 필요한 어린이들을 호출 해야하는 것 같습니다. 방문한 클래스가 수정 되더라도 방문자가 계속 일하기를 원하는 경우에는 약간 어리석은 것 같습니다.

실제 질문은 다음과 같습니다. 그들의 열거가 방문자 코드 대신 방문 된 코드에 의해 수행되는 패턴입니까?

도움이 되었습니까?

해결책

방문자 대상 ~이다 방문하는 것들의 구조를 알아야합니다. 그래도 괜찮습니다. 당신은 추정된 방문자가 방문하는 방법을 알고있는 각 유형의 특수 방문 작업을 작성하려면. 이를 통해 방문객은 실제로 방문하고 싶은 양과 순서대로 결정할 수 있습니다.

나무가 있다고 가정 해 봅시다. 한 방문자는 선주문 트래버스를 할 수 있고, 하나는 순서 대전선을 수행 할 수 있으며, 다른 방문자는 잎 노드에서만 행동 할 수 있습니다. 방문자 수업은 트리 클래스를 변경할 필요 없이이 모든 작업을 수행 할 수 있습니다.

방문자는 구조를 알고 있지만 반드시 방문자가 수행하는 작업이 모든 구조를 알고 있음을 의미하지는 않습니다. 방문자와 a를 결합 할 수 있습니다 명령. 방문자 객체에 명령 개체를 제공하면 방문자가 방문하는 각 항목에 대한 명령을 호출합니다.

간단한 작업을 원하고 컬렉션이 각 항목을 수행 할 수있게하려면 컬렉션이 반복자 그 자체로. 반복자가 제공하는 각각에 대한 기능을 호출하십시오.

다양한 순서로 트리의 노드를 반복하려면 나무가 여러 반복기를 제공해야합니다. 트리가 아직 지원하지 않도록 노드를 처리하려면 트리 클래스를 수정해야합니다.

다른 팁

예. 방문한 물체는 열거를 수행 할 수 있습니다 (즉, 필요한 어린이에게 호출). 이것을 여전히 "방문자"패턴이라고합니다 (사실, 디자인 패턴방문자의 첫 번째 샘플이 이런 식으로 수행합니다). 내 메이크업 예제 스 니펫 :

public void accept(Visitor visitor) {
  for (Node n : children) {
    n.accept(visitor);
  }
}

참고 : 아이들을 방문하기 위해 우리는 말할 수 없습니다. visitor.visit(n);. Java는 (인수의 런타임 클래스를 기반으로) 메소드를 동적으로 선택하지 않지만 (컴파일 타임 유형의 인수 유형에 따라) 방법을 선택합니다.

간단히 말해서, 방문자 패턴은 열거가 수행되는 방식과 직교적이라고 생각합니다. 어느 쪽이든 또는 전혀 열거 할 수 없습니다.

방문자가 방문한 요소가 어떤 요소로 구성되는지 알아야한다고 생각합니다. 자동차는 바퀴와 엔진으로 구성되어 있음을 알고 싶습니다. 그들이 정확히 결합 된 방법을 아는 것은 필요하지 않습니다. 다음 예를 고려하십시오. 내부자는 방문한 객체 구조를 알고 열거 자체를 수행합니다. 외부인은 그것을 알지 못하고 방문한 개체에 대한 열거를 위임합니다.

interface Visitable {
    void accept(Visitor visitor);
}

class WorkingRoom implements Visitable {
    public int number;
    WorkingRoom(int number) {
        this.number = number;
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

class BossRoom implements Visitable {
    public String bossName;
    BossRoom(String bossName) {
        this.bossName = bossName;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

interface Visitor{
    void visit(WorkingRoom workingRoom);
    void visit(BossRoom bossRoom);
    void visit(Office office);
}

class Office implements Visitable{
    public Visitable[] firstFloor;
    public Visitable[] secondFloor;
    public Visitable ceoRoom;
    public Office(){
        firstFloor = new Visitable[]{ new WorkingRoom(101),
                                        new WorkingRoom(102),
                                        new BossRoom("Jeff Atwood"),
                                        new WorkingRoom(103)};
        secondFloor = new Visitable[]{  new WorkingRoom(201),
                                        new WorkingRoom(202),
                                        new BossRoom("Joel Spolsky")};

        ceoRoom = new BossRoom("Bill Gates");
    }

    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public void showMeTheOffice(Visitor visitor, boolean sayPlease) {
        // Office manager decides the order in which rooms are visited
        for(int i=secondFloor.length-1; i >= 0; i--){
            secondFloor[i].accept(visitor);
        }
        if (sayPlease){
            ceoRoom.accept(visitor);
        }
        for (int i = 0; i < firstFloor.length; i++) {
            firstFloor[i].accept(visitor);
        }
    }
}

class Insider implements Visitor{
    public void visit(WorkingRoom workingRoom) {
        System.out.println("I> This is working room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("I> Hi, "+bossRoom.bossName);
    }

    public void visit(Office office) {
        // I know about office structure, so I'll just go to the 1st floor
        for(int i=0;i<office.firstFloor.length;i++){
            office.firstFloor[i].accept(this);
        }
    }
}

class Outsider implements Visitor{

    public void visit(Office office) {
        // I do not know about office structure, but I know they have a 
        // nice office manager
        // I'll just ask to show me the office
        office.showMeTheOffice(this, true);
    }

    public void visit(WorkingRoom workingRoom) {
        System.out.println("O> Wow, room #"+workingRoom.number);
    }

    public void visit(BossRoom bossRoom) {
        System.out.println("O> Oh, look, this is "+bossRoom.bossName);
    }
}

public class Main{
    public static void main(String[] args) {
        Office office = new Office(); // visited structure
        // visitor who knows about office structure
        Insider employee = new Insider(); 
        office.accept(employee);
        System.out.println();
        // visitor who does not know about exact office structure
        // but knows something else
        Outsider candidate = new Outsider(); 
        office.accept(candidate);

        // no enumeration at all, but still a visitor pattern
        Visitable v = new BossRoom("Linus Torvalds");
        v.accept(candidate);
    }
}

나는 열거없이 방문자 패턴을 광범위하게 사용하는 프로젝트를 가졌습니다. 우리는 기본 인터페이스 필드와 Stringfield, Numberfield 등과 같은 많은 클래스를 구현했습니다. 예를 들어 필드 유형에 따라 다른 작업을 수행해야했습니다 (예 : DB에서로드, 내보내기, XML 등). . 우리는 필드 인터페이스에서 메소드를 정의 할 수 있지만 프로젝트의 모든 단일 기능과 결합 할 수 있습니다. 열악한 필드는 HTML 및 RTF로 내보내기, 가져 오기, 렌더링 등을 알아야하지만 인스턴스를 사용할 수 있지만 가능합니다. 필드 인터페이스 구현 클래스는 시간이 지남에 따라 변경되었으며 새로운 필드 유형을 추가하고 추가하는 것을 잊을 수있었습니다.

else if (field instanceof NewlyAddedFieldType) {...}

어딘가에. 그래서 우리는 방문자 패턴을 사용하기로 결정했고

Visitor v = new XMLExportVisitor(outputStream);
field.accept(v);

모든 필드 구현에는 방법이 필요합니다

void accept(FieldVisitor visitor)

그런 다음 새로운 필드 인터페이스 구현을 추가하면 어떻게 든 구현해야합니다. 일반적으로 그것은입니다

visitor.visit(this);

여기서 새로 추가 된 수업입니다. 이것은 나를 추가하도록 강요합니다

void visit(NewlyAddedClass visited);

Fieldvisitor Interface에 이미 가지고있는 모든 Fieldvisitor 구현에서 구현할 수 있습니다. 따라서 이것에 대해 무언가를하는 것을 잊어 버리면 컴파일러 오류가 발생합니다. 이 경우 열거는 방문한 구조 및 방문자 외부에서 수행되었습니다. 그러나 나는 여전히 방문자 패턴의 유효한 사례라고 생각합니다. 구현하기가 조금 더 어렵지만 사용하기 쉽고 안전합니다.

그만큼 계층 적 방문자 패턴 레벨에 들어가고 떠나기위한 이벤트를 추가하는 다른 접근법을 설명합니다. 관련 토론 페이지 방문자 또는 컨테이너 내에 반복에 대한 주장을 제시합니다. 여기에는 일반 트리가 있고 다르게 반복 해야하는 경우 나에게 의미가있는 외부 반복기를 사용한다는 제안이 포함되어 있습니다.

내 것을 되돌아보고 Oofrep 방문자 방문 할 일련의 다양한 수준의 수준이 있었고 다음과 같은 방법 내에서 반복을 가졌습니다.

void
oofRepVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
    VisitBandList(inBands);
}


void
oofRepVisitor::VisitBandList(oofRepBandList& inBands)
{
    EnterLevel();
    const unsigned long numBands = inBands.count();
    for (unsigned long i=0; i<numBands; i++) {
        oofRepBand* theBand = inBands.value(i);
        assert(theBand);
        VisitTypedBand(theBand);
    }
    LeaveLevel();
}

재정의와 함께

void
OOF_repXMLlayoutVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
    oofRepStreamEnv::out() << mIdentities.getIndentString();
    if (inBands.keepTogether())
        oofRepStreamEnv::out()  << "<header>\n";    
    else  // default is ON, and simplifies XML
        oofRepStreamEnv::out()  << "<header keepTogether='false'>\n";
    VisitBandList(inBands);
    oofRepStreamEnv::out() 
        << mIdentities.getIndentString()
        << "</header>\n";
}

이것에 대한 설명을 살펴보십시오 기사.

에서 위키:

객체 지향 프로그래밍 및 소프트웨어 엔지니어링에서 방문자 설계 패턴은 알고리즘을 작동하는 객체 구조에서 분리하는 방법입니다. 이 분리의 실질적인 결과는 해당 구조를 수정하지 않고 기존 객체 구조에 새로운 작업을 추가하는 능력입니다. 따라서 방문자 패턴을 사용하면 개방형/폐쇄 된 원리를 준수하는 데 도움이됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top