방문자 패턴 이해


16

GUI 컨트롤을 나타내는 클래스 계층이 있습니다. 이 같은:

Control->ContainerControl->Form

다양한 작업을 수행하는 객체에서 작동하는 일련의 알고리즘을 구현해야하며 방문자 패턴이 가장 깨끗한 솔루션이라고 생각합니다. 객체 계층의 Xml 표현을 만드는 알고리즘을 예로 들어 보겠습니다. '클래식'접근법을 사용하면 다음과 같이 할 수 있습니다.

public abstract class Control
{
    public virtual XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = document.CreateElement(this.GetType().Name);
        // Create element, fill it with attributes declared with control
        return xml;
    }
}

public abstract class ContainerControl : Control
{
    public override XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = base.ToXML(document);
        // Use forech to fill XmlElement with child XmlElements
        return xml;
    }
}

public class Form : ContainerControl
{
    public override XmlElement ToXML(XmlDocument document)
    {
        XmlElement xml = base.ToXML(document);
        // Fill remaining elements declared in Form class
        return xml;
    }
}

그러나 방문자 패턴 으로이 작업을 수행하는 방법을 잘 모르겠습니다. 이것이 기본 구현입니다.

public class ToXmlVisitor : IVisitor
{
    public void Visit(Form form)
    {
    }
}

추상 클래스조차도 구현에 도움이되므로 ToXmlVisitor에서 올바르게 수행하는 방법을 모르겠습니까?

방문자 패턴을 고려하는 이유는 일부 알고리즘에는 클래스가 구현되는 프로젝트에서 사용할 수없는 참조가 필요하고 많은 다른 알고리즘이 있으므로 큰 클래스를 피하기 때문입니다.


귀하의 질문은 무엇인가?
gnat

기본적으로 방문자 패턴을 사용하여 ToXml () 메서드를 다시 작성하는 방법
Nezreli


링크 주셔서 감사합니다. 동적 디스패치는 기존 방문자 패턴을 단순화하지만 크게 변경되지는 않습니다.
Nezreli

@Nezreli 그렇습니다. 처리하는 Windows Forms 컨트롤과 같이 방문자 패턴을 지원하지 않는 클래스와 함께 작동합니다.
Kris Vandermotten

답변:


17

방문자 패턴은 단일 바인딩 만 지원하는 프로그래밍 언어에서 이중 바인딩을 시뮬레이션하는 메커니즘입니다. 불행히도 그 진술은 많은 것을 명확하게하지 않을 수 있으므로 간단한 예를 들어 설명하겠습니다.

.NET 및 C #에서 사용중인 플랫폼 인 개체를 사용하여 문자열로 변환 할 수 있습니다. ToString() 함수를 . 해당 funtion이 수행하는 작업, 즉 실행중인 코드는 적용하는 객체 유형에 따라 다릅니다 (가상 방법 임). 어떤 코드가 실행되는지는 객체의 한 유형에 따라 다르므로 사용되는 메커니즘을 단일 바인딩이라고합니다.

그러나 객체마다 문자열을 변환하는 여러 가지 방법을 원한다면 어떻게해야합니까? 객체를 문자열로 변환하는 두 가지 방법을 원한다면 실행되는 코드가 두 가지에 달려 있습니다. 변환 할 객체뿐만 아니라 변환하려는 방식도 무엇입니까?

이중 바인딩이 있으면 멋지게 해결할 수 있습니다. 그러나 C #을 포함한 대부분의 OO 언어는 단일 바인딩 만 지원합니다.

방문자 패턴은 이중 바인딩을 두 개의 성공적인 단일 바인딩으로 전환하여 문제를 해결합니다.

위의 예에서, 변환 알고리즘을 구현하는 오브젝트에서 두 번째 가상 메소드를 호출하는 변환 할 오브젝트에서 가상 메소드를 사용합니다.

그러나 이는 알고리즘을 적용하려는 객체가 이것과 공동 작업을해야한다는 것을 의미합니다. 방문자 패턴을 지원해야합니다.

방문자 패턴을 지원하지 않는 .NET의 Windows Forms 클래스를 사용하고있는 것 같습니다. 보다 구체적으로, 그들은 가지고 public virtual void Accept(IVisitor)있지 않은 방법 이 필요합니다 .

대체 대안은 무엇입니까? .NET은 단일 바인딩을 지원할뿐만 아니라 동적 바인딩도 지원하므로 이중 바인딩보다 훨씬 약합니다.

문제를 해결할 수있는 해당 기술을 적용하는 방법에 대한 자세한 내용은 잘 이해하는 경우 Farewell Visitor를 참조하십시오 .

최신 정보:

특정 문제에 기술을 적용하려면 먼저 확장 방법을 정의하십시오.

public static XmlDocument ToXml(this Control control)
{
    XmlDocument xml = new XmlDocument();
    XmlElement root = xml.CreateElement(control.GetType().Name);
    xml.AppendChild(root);

    Visit(control, xml, root);

    return xml;
}

동적 디스패처를 작성하십시오.

private static void Visit(Control control, XmlDocument xml, XmlElement root)
{
    dynamic dynamicControl = control; //notice the 'dynamic' type.
                                      //this is the key to dynamic dispatch

    VisitCore(dynamicControl, xml, root);
}

그런 다음 특정 방법을 작성하십시오.

private static void VisitCore(Control control, XmlDocument xml, XmlElement root)
{
    // TODO: specific Control handling
}

private static void VisitCore(ContainerControl control, XmlDocument xml, XmlElement root)
{
    // call the "base" method
    VisitCore(control as Control, xml, root);

    // TODO: specific ContainerControl handling
    // for example:
    foreach (Control child in control.Controls)
    {
        XmlElement element = xml.CreateElement(child.GetType().Name);
        root.AppendChild(element);

        // call the dynamic dispatcher method
        Visit(child, xml, element);
    }
}

private static void VisitCore(Form control, XmlDocument xml, XmlElement root)
{
    // call the "base" method
    VisitCore(control as ContainerControl, xml, root);

    // TODO: specific Form handling
}

.NET의 동적 디스패치는 실제로 매우 강력합니다 .. 그러나 약간 느릴 수 있음을 알았습니다 ... 느리지 만 단일 클래스의 코드에서 여러 클래스의 sevral 라인과 방문자와의 인터페이스를
취하는 것

여전히 ToXml 알고리즘을 사용하면 상속 체인을 통해 모든 유형을 '방문'해야하므로 동적 디스패치로 문제가 해결되지 않습니다. 내 예제에서는 성공적인 XML 변환을 위해 Control, ContainterControl 및 Form을 순서대로 방문해야합니다.
Nezreli

@ Nezreli 문제를 해결할 수 있습니다. 방법을 보여주기 위해 답변을 업데이트했습니다.
Kris Vandermotten

동적 변수 정의에 주석을 추가 할 수있는 권한을 가졌습니다. 그것을 발견하기 전에 코드를 두 번 읽었으며 전체 이야기의 핵심입니다.
Cristi Diaconescu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.