Visitor pattern

Giới thiệu

Trong thiết kế hướng đối tượng, Visitor là mẫu thiết kế (Design Patterns) cho phép định nghĩa các thao tác (operations) trên một tập hợp các đối tượng (objects) không đồng nhất (về kiểu) mà không làm thay đổi định nghĩa về lớp (classes) của các đối tượng đó. Để đạt được điều này, trong mẫu thiết kế visitor ta định nghĩa các thao tác trên các lớp tách biệt gọi các lớp visitors, các lớp này cho phép tách rời các thao tác với các đối tượng mà nó tác động đến. Với mỗi thao tác được thêm vào, một lớp visitor tương ứng được tạo ra.

Thiết kế

Thiết kế của mẫu visitor gồm 3 phần:

Các lớp visitor

Các lớp visitor định nghĩa các thao tác tương tác trên các đối tượng. Các lớp này là cài đặt của một giao diện chung là VisitorInterface trong đó định nghĩa các phương thức dạng visit(ObjectType object),với mỗi kiểu (lớp) của các đối tượng ta có một phương thức visit với tham số truyền vào là một thực thể của kiểu đó. Mỗi phương thức như thế có nhiệm vụ xử lý trên các thực thể của lớp tương ứng. Ví dụ ta có tập hợp các đối tượng là các thực thể của hai kiểu(lớp) ClassA và ClassB thì VisitorInterface sẽ bao gồm hai phương thức:

visit(ClassA obj)
visit(ClassB obj)

Các lớp của các đối tượng trong tập hợp các đối tượng

Để các thao tác định nghĩa trong các lớp visitor có thể thực hiện được, các lớp của các đối tượng trong tập hợp các đối tượng cần cài đặt giao diện Visitable trong đó có một phương thức accept(VisitorInterface visitor). Trong cài đặt của phương thức này ta gọi hàm visit của visitor với tham số truyền vào chính là đối tượng gọi:

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

Client

Các client muốn thực thi thao tác của visitor trên tập hợp các đối tượng cần phải tạo ra một thực thể của lớp vistor tương ứng với thao tác đó, và sau đó gọi phương thức accept của từng đối tượng trong tập hợp các đối tượng với tham số là thực thể visitor vừa tạo ra. (Xem ví dụ để hiểu rõ hơn)

Ví dụ

Sau đây là một ví dụ đơn giản minh họa áp dụng của mẫu thiết kế trên và cũng để hiểu rõ thêm về cài đặt của nó.

Sơ đồ lớp của ví dụ bằng UML

Tập tin:Wiki visitor.png

Cài đặt bằng Java

Sau đây là cài đặt của ví dụ trên bằng ngôn ngữ Java
interface Visitor {
    public void visit(Wheel wheel);
    public void visit(Engine engine);
    public void visit(Body body);
    public void visit(Car car);}//differing from above displayed UML: Additional use of an interface 'Element'interface Element {
    public void accept(Visitor visitor);}/* Concrete element */class Wheel implements Element {
    private String name;
    Wheel(String name) {
        this.name = name;
    }
    String getName() {
        return this.name;
    }
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }}/* Concrete element */class Engine implements Element{
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }}/* Concrete element */class Body implements Element{
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }}/* Concrete element */class Car implements Element {
    private Engine  engine = new Engine();
    private Body    body   = new Body();
    private Wheel[] wheels 
        = { new Wheel("front left"), new Wheel("front right"),
            new Wheel("back left"), new Wheel("back right")  };
    public void accept(Visitor visitor) {
        visitor.visit(this);
        engine.accept(visitor);
        body.accept(visitor);
        for(int i=0; i<wheels.length; ++i)
            wheels[i].accept(visitor);
    }}/* Concrete visior */class PrintVisitor implements Visitor {
    public void visit(Wheel wheel) {
        System.out.println("Visiting "+wheel.getName()
                            +" wheel");
    }
    public void visit(Engine engine) {
        System.out.println("Visiting engine");
    }
    public void visit(Body body) {
        System.out.println("Visiting body");
    }
    public void visit(Car car) {
        System.out.println("Visiting car");
    }}public class VisitorDemo {
    public static void main(String[] args){
        Car car = new Car();
        Visitor visitor = new PrintVisitor();
        car.accept(visitor);
    }}