Visitorパターンとは | GoFデザインパターン

記事内に広告が含まれています。

Visitorパターンは、GoFデザインパターンの中でも重要な1つで、オブジェクト構造の各要素に対して新しい操作を追加できる柔軟なパターンです。

本記事では、Visitorパターンの概要、使い方、およびJava、C++、C#、VB.NETでの実装サンプルを紹介します。

Visitorパターンとは

Visitorパターンは、オブジェクトの構造が変わらないまま新しい操作を追加する方法を提供するデザインパターンです。

これは、操作を要素ごとに外部から追加するための仕組みを提供し、構造の変化に対して柔軟に対応することが可能です。

Visitorパターンの目的

Visitorパターンの主な目的は、オブジェクト構造に対して操作を追加したい場合に、その構造のクラスを変更せずに新しい操作を定義できることです。

これにより、再利用性や保守性が向上します。

Visitorパターンの使い方

Visitorパターンは、異なる型のオブジェクトに対して同様の操作を実行する必要がある場合に有効です。

具体的な実装では、オブジェクトを訪問する「Visitor」インターフェースを定義し、各オブジェクトが自分自身を訪問させるためのメソッドを提供します。

基本的な構造

Visitorパターンの基本構造は以下の通りです:

  • Visitorインターフェース:操作を定義する。
  • 具体的なVisitor:各要素に対する操作を実装する。
  • 要素インターフェース:Visitorを受け入れるためのメソッドを定義する。
  • 具体的な要素:要素の具体的な処理を実装する。

Visitorパターン実装サンプル

以下に、Java、C++、C#、VB.NETそれぞれでVisitorパターンを実装したサンプルを示します。

JavaでのVisitorパターン実装


// Visitorインターフェース
interface Visitor {
    void visit(ElementA element);
    void visit(ElementB element);
}

// Elementインターフェース
interface Element {
    void accept(Visitor visitor);
}

// 具体的なElementA
class ElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public String operationA() {
        return "ElementAの操作";
    }
}

// 具体的なElementB
class ElementB implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public String operationB() {
        return "ElementBの操作";
    }
}

// 具体的なVisitor
class ConcreteVisitor implements Visitor {
    public void visit(ElementA element) {
        System.out.println("Visitorは" + element.operationA() + "を実行しています");
    }
    public void visit(ElementB element) {
        System.out.println("Visitorは" + element.operationB() + "を実行しています");
    }
}

// 実行例
public class VisitorPatternExample {
    public static void main(String[] args) {
        Element[] elements = { new ElementA(), new ElementB() };
        Visitor visitor = new ConcreteVisitor();
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

C++でのVisitorパターン実装


// Visitorクラス
class Visitor {
public:
    virtual void visit(class ElementA* e) = 0;
    virtual void visit(class ElementB* e) = 0;
};

// Elementクラス
class Element {
public:
    virtual void accept(Visitor& v) = 0;
};

// ElementAクラス
class ElementA : public Element {
public:
    void accept(Visitor& v) override {
        v.visit(this);
    }
    std::string operationA() {
        return "ElementAの操作";
    }
};

// ElementBクラス
class ElementB : public Element {
public:
    void accept(Visitor& v) override {
        v.visit(this);
    }
    std::string operationB() {
        return "ElementBの操作";
    }
};

// ConcreteVisitorクラス
class ConcreteVisitor : public Visitor {
public:
    void visit(ElementA* e) override {
        std::cout << "Visitorは" << e->operationA() << "を実行しています\n";
    }
    void visit(ElementB* e) override {
        std::cout << "Visitorは" << e->operationB() << "を実行しています\n";
    }
};

// 実行例
int main() {
    Element* elements[] = { new ElementA(), new ElementB() };
    ConcreteVisitor visitor;
    for (Element* element : elements) {
        element->accept(visitor);
    }
    return 0;
}

C#でのVisitorパターン実装


// Visitorインターフェース
interface Visitor {
    void Visit(ElementA element);
    void Visit(ElementB element);
}

// Elementインターフェース
interface Element {
    void Accept(Visitor visitor);
}

// ElementAクラス
class ElementA : Element {
    public void Accept(Visitor visitor) {
        visitor.Visit(this);
    }
    public string OperationA() {
        return "ElementAの操作";
    }
}

// ElementBクラス
class ElementB : Element {
    public void Accept(Visitor visitor) {
        visitor.Visit(this);
    }
    public string OperationB() {
        return "ElementBの操作";
    }
}

// ConcreteVisitorクラス
class ConcreteVisitor : Visitor {
    public void Visit(ElementA element) {
        Console.WriteLine("Visitorは" + element.OperationA() + "を実行しています");
    }
    public void Visit(ElementB element) {
        Console.WriteLine("Visitorは" + element.OperationB() + "を実行しています");
    }
}

// 実行例
class Program {
    static void Main() {
        Element[] elements = { new ElementA(), new ElementB() };
        Visitor visitor = new ConcreteVisitor();
        foreach (Element element in elements) {
            element.Accept(visitor);
        }
    }
}

VB.NETでのVisitorパターン実装


' Visitorインターフェース
Public Interface Visitor
    Sub Visit(ByVal element As ElementA)
    Sub Visit(ByVal element As ElementB)
End Interface

' Elementインターフェース
Public Interface Element
    Sub Accept(ByVal visitor As Visitor)
End Interface

' ElementAクラス
Public Class ElementA
    Implements Element
    Public Sub Accept(ByVal visitor As Visitor) Implements Element.Accept
        visitor.Visit(Me)
    End Sub
    Public Function OperationA() As String
        Return "ElementAの操作"
    End Function
End Class

' ElementBクラス
Public Class ElementB
    Implements Element
    Public Sub Accept(ByVal visitor As Visitor) Implements Element.Accept
        visitor.Visit(Me)
    End Sub
    Public Function OperationB() As String
        Return "ElementBの操作"
    End Function
End Class

' ConcreteVisitorクラス
Public Class ConcreteVisitor
    Implements Visitor
    Public Sub Visit(ByVal element As ElementA) Implements Visitor.Visit
        Console.WriteLine("Visitorは" & element.OperationA() & "を実行しています")
    End Sub
    Public Sub Visit(ByVal element As ElementB) Implements Visitor.Visit
        Console.WriteLine("Visitorは" & element.OperationB() & "を実行しています")
    End Sub
End Class

' 実行例
Module Program
    Sub Main()
        Dim elements As Element() = {New ElementA(), New ElementB()}
        Dim visitor As New ConcreteVisitor()
        For Each element As Element In elements
            element.Accept(visitor)
        Next
    End Sub
End Module

まとめ

Visitorパターンは、オブジェクトの構造を変更せずに新しい操作を追加するための柔軟な方法を提供します。

これにより、システム全体の保守性が向上し、再利用可能なコードを実現できます。

Java、C++、C#、VB.NETなどの異なるプログラミング言語での実装例を通して、Visitorパターンの理解が深まったかと思います。

実際のプロジェクトでこのパターンを活用し、より効率的なシステム設計を目指しましょう。

オブジェクト指向プログラミングにおけるGoFの23のデザインパターン
デザインパターンは、ソフトウェア設計の問題を効果的に解決するための再利用可能な解決策です。本記事では、GoF(Gang ...
タイトルとURLをコピーしました