Hiểu mô hình khách truy cập


16

Tôi có một hệ thống phân cấp các lớp đại diện cho các điều khiển GUI. Một cái gì đó như thế này:

Control->ContainerControl->Form

Tôi phải triển khai một loạt các thuật toán làm việc với các đối tượng làm nhiều việc khác nhau và tôi nghĩ rằng mô hình của Khách truy cập sẽ là giải pháp sạch nhất. Ví dụ như một thuật toán tạo ra biểu diễn Xml của hệ thống phân cấp các đối tượng. Sử dụng phương pháp 'cổ điển' tôi sẽ làm điều này:

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

Nhưng tôi không chắc làm thế nào để làm điều này với mẫu khách truy cập. Đây là cách thực hiện cơ bản:

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

Vì ngay cả các lớp trừu tượng cũng giúp triển khai, tôi không chắc làm thế nào để làm điều đó đúng trong ToXmlVisitor?

Lý do tôi đang xem xét mẫu của Khách truy cập là một số thuật toán sẽ cần các tài liệu tham khảo không có sẵn trong dự án nơi các lớp được triển khai và có một số thuật toán khác nhau nên tôi tránh các lớp lớn.


câu hỏi của bạn là gì?
gnat

Về cơ bản cách viết lại phương thức ToXml () bằng cách sử dụng mẫu khách truy cập.
Nezreli


Cảm ơn các liên kết. Công văn động đơn giản hóa mô hình khách truy cập truyền thống nhưng nó không thay đổi nhiều.
Nezreli

@Nezreli Vâng, đúng vậy. Nó hoạt động với các lớp không hỗ trợ mẫu Khách truy cập, chẳng hạn như các điều khiển Windows Forms mà bạn đang xử lý.
Kris Vandermotten

Câu trả lời:


17

Mẫu khách truy cập là một cơ chế để mô phỏng liên kết kép trong các ngôn ngữ lập trình chỉ hỗ trợ liên kết đơn. Thật không may, tuyên bố đó có thể không làm rõ mọi thứ rất nhiều, vì vậy hãy để tôi giải thích với một ví dụ đơn giản.

Trong .NET và C #, nền tảng bạn đang sử dụng, các đối tượng có thể được chuyển đổi thành chuỗi bằng ToString()hàm. Chức năng đó làm gì, tức là mã đang được thực thi, tùy thuộc vào loại đối tượng bạn đang áp dụng nó (đó là một phương thức ảo). Mã nào được thực thi phụ thuộc vào một thứ, một loại đối tượng, do đó cơ chế được sử dụng được gọi là liên kết đơn.

Nhưng nếu tôi muốn có nhiều hơn một cách để chuyển đổi một đối tượng thành một chuỗi, cho mỗi loại đối tượng khác nhau thì sao? Điều gì xảy ra nếu tôi muốn có hai cách để chuyển đổi các đối tượng thành các chuỗi, để mã được thực thi phụ thuộc vào hai điều: không chỉ đối tượng được chuyển đổi, mà còn cả cách chúng ta muốn chuyển đổi nó?

Điều đó có thể được giải quyết độc đáo nếu chúng ta có ràng buộc kép. Nhưng hầu hết các ngôn ngữ OO, bao gồm C #, chỉ hỗ trợ liên kết đơn.

Mẫu khách truy cập giải quyết vấn đề, bằng cách biến ràng buộc kép thành hai ràng buộc đơn thành công.

Trong ví dụ của chúng tôi ở trên, nó sẽ sử dụng một phương thức ảo trong đối tượng để chuyển đổi, gọi phương thức ảo thứ hai trong đối tượng thực hiện thuật toán chuyển đổi.

Nhưng điều đó ngụ ý rằng đối tượng mà bạn muốn áp dụng thuật toán cần cộng tác với điều này: nó cần phải có sự hỗ trợ cho mẫu khách truy cập được đưa vào.

Có vẻ như bạn đang sử dụng các lớp Windows Forms của .NET, không hỗ trợ cho mẫu khách truy cập. Cụ thể hơn, họ sẽ cần phải có một public virtual void Accept(IVisitor)phương pháp, mà rõ ràng là họ không có.

Vì vậy, những gì thay thế? Vâng, .NET không chỉ hỗ trợ liên kết đơn, nó còn hỗ trợ liên kết động, thậm chí còn ngang hàng hơn so với liên kết kép.

Để biết thêm thông tin về cách áp dụng kỹ thuật đó, điều này sẽ cho phép bạn giải quyết vấn đề của mình (nếu tôi hiểu rõ về nó), hãy xem Farewell visitor .

CẬP NHẬT:

Để áp dụng kỹ thuật cho vấn đề cụ thể của bạn, trước tiên, hãy xác định phương thức mở rộng của bạn:

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

Tạo bộ điều phối động:

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

Sau đó điền vào các phương pháp cụ thể:

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
}

công văn động trong .NET thực sự khá mạnh mẽ .. tuy nhiên tôi nhận thấy nó có thể hơi ... tốt .. chậm, nhưng nó thực hiện trong một dòng mã duy nhất có các dòng thứ bảy trong nhiều lớp và giao diện với khách truy cập
Newtopian

Tuy nhiên, công văn động sẽ không giải quyết được vấn đề của tôi vì thuật toán ToXml của tôi yêu cầu tôi phải 'truy cập' tất cả các loại lên chuỗi kế thừa. Trong ví dụ của tôi, nó cần truy cập Control, ContainterControl và Form để có một chuyển đổi XML thành công.
Nezreli

@Nezreli Nó có thể giải quyết vấn đề của bạn, tôi đã cập nhật câu trả lời của mình để chỉ cho bạn cách.
Kris Vandermotten

Tôi đã cho phép để thêm một nhận xét cho định nghĩa biến động. Tôi đã mất hai lần đọc mã trước khi tôi phát hiện ra nó và đó là chìa khóa cho toàn bộ câu chuyện.
Cristi Diaconescu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.