2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonで実装するVisitorパターン:処理とデータ構造の分離を美しく保つ

Posted at

概要

Visitor(ビジター)パターンは、
データ構造(要素)と、それに対する処理(アルゴリズム)を分離し、新しい処理を追加する際に構造を変更せずに済む設計を実現するパターンである。

構文木の探索や、異なる型のノードに対して異なる処理を適用する際に特に有効。
OOPにおけるダブルディスパッチの概念に基づく設計


1. なぜVisitorが必要か?

❌ 要素クラスが処理を内包しすぎて、追加変更が困難になる

class Node:
    def evaluate(self): ...
    def render(self): ...
    def export(self): ...

→ 処理が増えるたびにデータ構造に手を加える必要が生じる


✅ 処理をVisitorとして外部化することで柔軟に拡張

node.accept(Evaluator())
node.accept(Renderer())
node.accept(Exporter())

構造は固定、処理だけを独立に追加可能


2. 基本構造

✅ Element(訪問される側)

class Node:
    def accept(self, visitor):
        raise NotImplementedError

✅ Concrete Elements

class NumberNode(Node):
    def __init__(self, value):
        self.value = value

    def accept(self, visitor):
        return visitor.visit_number(self)

class AddNode(Node):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def accept(self, visitor):
        return visitor.visit_add(self)

✅ Visitor(訪問者インターフェース)

class Visitor:
    def visit_number(self, node):
        raise NotImplementedError

    def visit_add(self, node):
        raise NotImplementedError

✅ Concrete Visitor(処理の実体)

class Evaluator(Visitor):
    def visit_number(self, node):
        return node.value

    def visit_add(self, node):
        return node.left.accept(self) + node.right.accept(self)

✅ 使用例

# 3 + 7
tree = AddNode(NumberNode(3), NumberNode(7))
result = tree.accept(Evaluator())
print(result)  # → 10

3. Python的応用:関数ディスパッチを使ったシンプルなVisitor風設計

def visit(node):
    if isinstance(node, NumberNode):
        return node.value
    elif isinstance(node, AddNode):
        return visit(node.left) + visit(node.right)

小規模なら関数ベースで簡潔にVisitorのような振る舞いを表現可能


4. 実務ユースケース

✅ 抽象構文木(AST)の走査と評価

→ コンパイラ、インタプリタにおけるコード解析・評価・変換


✅ データツリーのシリアライズ(JSON/XML/HTML)

→ 要素構造を保持しながら出力形式だけを柔軟に切り替え


✅ バリデーションやリント処理の注入

→ 各要素への検査ロジックをVisitorとして独立管理


✅ グラフィカルUIコンポーネントへの操作適用

→ コンポーネントツリー全体に共通操作(例:再描画・更新)を適用


5. よくある誤用と対策

❌ Visitorクラスが肥大化しがち

→ ✅ 用途別に複数のVisitorへ分割し、単一責任を守る


❌ accept メソッドの切り分けが曖昧

→ ✅ ノードタイプごとに訪問メソッドを明示的に定義


❌ Visitorの種類を動的に追加できない設計

→ ✅ 動的ディスパッチや関数型設計を併用して柔軟性を補完


結語

Visitorパターンとは、“構造はそのまま、振る舞いだけを外から静かに訪れる設計”である。

  • データ構造と処理を分離することで、拡張性と保守性を飛躍的に向上
  • 処理の差し替え・追加が構造に影響せず、システムの安定性を高める
  • Pythonでは動的なディスパッチやOOPの柔軟性を活かして、実用的かつ読みやすいVisitorの実装が可能

Pythonicとは、“データと処理の独立性を保ち、変化に備えること”。
Visitorパターンはその独立性を、訪問という優雅な構造に昇華した技法である。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?