Skeleton of GOF's Design Pattern


VISITORの骸骨

VISITOR

このパターンは、データ構造に変更を加えずに、新しいオペレーションを追加するためのパターンです。

VISITOR は、処理対象となる Element と、個々のクラスに対する処理を記述した Visitor の2つで構成されます。2つのオブジェクト間のプロトコルが定義されており、Elementには、accept(Visitor v) を定義し、Visitor は、visit(xxElement e) を定義する必要があります。

VISITOR パターンは、オブジェクトのクラスを特定するための型チェック機構を備えているため、扱っているオブジェクトのクラスが曖昧になる COMPOSITE パターン等のデータ構造において、処理の追加を実現できます。

具体的な例を知りたい方は、VISITOR で四則演算?を参照してください。


■ 『VISITORの骸骨』の構造


■ 『VISITORの骸骨』の特徴的な協調関係


■ 『VISITORの骸骨』 プログラム・コード

□ Java2版
// Copyright(C) 2000-2003 Yoshinori Oota All rights reserved.

import java.util.*;

public class VisitorSample {
    static Component makeComposite() {
        Composite component1 = new Composite();
        component1.add(new Leaf());
        component1.add(new Leaf());

        Composite component2 = new Composite();
        component2.add(new Leaf());
        component2.add(new Leaf());
        component2.add(component1);
        return component2;
    }
    static public void main(String[] args) {
        Component component = makeComposite();

        //各要素のメッセージを出力しよう!
        DumpVisitor dump = new DumpVisitor();
        component.Accept(dump);

        //要素のダンプをとろう!
        CountVisitor counter = new CountVisitor();
        component.Accept(counter);
        counter.print();
    }
}

abstract class Visitor {
    abstract public void VisitComposite(Composite composite);
    abstract public void VisitLeaf(Leaf leaf);
}

class DumpVisitor extends Visitor {
    private int _depth = 0;
    public void VisitComposite(Composite composite) {
        for (int i = 0; i < _depth; ++i) {
            System.out.print("    ");
        }
        System.out.println("+ Composite");
        ++_depth;
    }
    public void VisitLeaf(Leaf leaf) {
        for (int i = 0; i < _depth; ++i) {
            System.out.print("    ");
        }
        System.out.println("- Leaf");
    }
}

class CountVisitor extends Visitor {
    private int _comp_count = 0;
    private int _leaf_count = 0;
    public void VisitComposite(Composite composite) {
        ++_comp_count;
    }
    public void VisitLeaf(Leaf leaf) {
        ++_leaf_count;
    }
    public void print() {
        System.out.println("Composite: " + _comp_count);
        System.out.println("Leaf: " + _leaf_count);
    }
}

abstract class Component  {
    abstract public void Accept(Visitor v);
}

class Leaf extends Component {
    public void Accept(Visitor v) {
        v.VisitLeaf(this);
    }
}

class Composite extends Component {
    private LinkedList _children = new LinkedList();
    public void add(Component component) {
        _children.add(component);
    }
    public void Accept(Visitor v) {
        v.VisitComposite(this);
        ListIterator it = _children.listIterator();
        while (it.hasNext()) {
            Component component = (Component)it.next();
            component.Accept(v);
        }
    }
}

○ C++版
// Copyright(C) 2003 Yoshinori Oota All rights reserved.

#include <list>
#include <iostream>
using namespace std;

class Visitor;

class Component {
public:
    Component();
    virtual ~Component();
    virtual void Accept(Visitor* v) = 0;
};

class Leaf : public Component {
public:
    Leaf();
    virtual ~Leaf();
    virtual void Accept(Visitor* v);
};

class Composite : public Component {
public:
    Composite();
    virtual ~Composite();
    virtual void Accept(Visitor* v);
    void add(Component* component);
private:
    list<Component*> children_;
};

class Visitor {
public:
    Visitor();
    virtual ~Visitor();
    virtual void VisitLeaf(Leaf* c) = 0;
    virtual void VisitComposite(Composite* c) = 0;
};

class DumpVisitor : public Visitor {
public:
    DumpVisitor();
    virtual ~DumpVisitor();
    virtual void VisitLeaf(Leaf* c);
    virtual void VisitComposite(Composite* c);
private:
    int depth_;
};

class CountVisitor : public Visitor {
public:
    CountVisitor();
    virtual ~CountVisitor();
    virtual void VisitLeaf(Leaf* c);
    virtual void VisitComposite(Composite* c);
    void print() const;
private:
    int leaf_count_;
    int comp_count_;
};

Component::Component() { }
Component::~Component() { }
Leaf::Leaf() { }
Leaf::~Leaf() { }
void Leaf::Accept(Visitor* v) {
    v->VisitLeaf(this);
}

Composite::Composite() { }
Composite::~Composite() {
    list<Component*>::iterator it = children_.begin();
    while (it != children_.end()) {
        delete (*it);
        ++it;
    }
}
void Composite::Accept(Visitor* v) {
    v->VisitComposite(this);
    list<Component*>::iterator it = children_.begin();
    while (it != children_.end()) {
        (*it)->Accept(v);
        ++it;
    }
}
void Composite::add(Component* c) {
    children_.push_back(c);
}
Visitor::Visitor() { }
Visitor::~Visitor() { }
DumpVisitor::DumpVisitor() : depth_(0) { }
DumpVisitor::~DumpVisitor() { }
void DumpVisitor::VisitLeaf(Leaf* c) {
    for (int i = 0; i < depth_; ++i) {
        cout << "    ";
    }
    cout << "- Leaf" << endl;
}
void DumpVisitor::VisitComposite(Composite* c) {
    for (int i = 0; i < depth_; ++i) {
        cout << "    ";
    }
    cout << "+ Composite" << endl;
    ++depth_;
}
CountVisitor::CountVisitor() : leaf_count_(0), comp_count_(0) { }
CountVisitor::~CountVisitor() { }
void CountVisitor::VisitLeaf(Leaf* c) {
    ++leaf_count_;
}
void CountVisitor::VisitComposite(Composite* c) {
    ++comp_count_;
}
void CountVisitor::print() const {
    cout << "Composite: " << comp_count_ << endl;
    cout << "Leaf: " << leaf_count_ << endl;
}

Component* makeComposite() {
    Composite* component1 = new Composite();
    component1->add(new Leaf());
    component1->add(new Leaf());

    Composite* component2 = new Composite();
    component2->add(new Leaf());
    component2->add(new Leaf());
    component2->add(component1);

    return component2;
}

int main() {
    Component* component = makeComposite();

    DumpVisitor* dump = new DumpVisitor();
    component->Accept(dump);
    delete dump;

    CountVisitor* counter = new CountVisitor();
    component->Accept(counter);
    counter->print();
    delete counter;

    delete component;
}

○ C版
/* Copyright(C) 2009 Yoshinori Oota All rights reserved. */
#include <stdio.h>
#include <stdlib.h>
struct Component;
struct Visitor;
void indent(int n);

enum COMPONENT_TYPE { LEAF ,COMPOSITE };
enum VISITOR_TYPE { DUMP ,COUNT };

/* Component List */
struct ComponentList {
    struct Component* component_;
    struct ComponentList* next_;
};
struct ComponentList* New_ComponentList(struct Component* component);
void Delete_ComponentList(struct ComponentList* list);

/* Component Interface */
struct Component {
    enum COMPONENT_TYPE type_;
    struct ComponentList* child_top_;
    struct ComponentList* child_last_;
    void (*accept)(struct Component* pthis ,struct Visitor* v);
    void (*add)(struct Component* pthis ,struct Component* child);
    void (*Operation)(struct Component* pthis ,int n);
};
struct Component* New_Component(enum COMPONENT_TYPE type); 
void Delete_Component(struct Component* component);
void Leaf_accept (struct Component* pthis ,struct Visitor* v);
void Leaf_add(struct Component* pthis ,struct Component* child);
void Leaf_Operation(struct Component* pthis ,int n);
void Composite_accept(struct Component* pthis ,struct Visitor* v);
void Composite_add(struct Component* pthis ,struct Component* child); 
void Composite_Operation(struct Component* pthis ,int n);

/* Visitor Interface */
struct Visitor {
    int depth_;   /* for Dump Visitor */
    int leaf_count_;  /* for Count Visitor */
    int comp_count_;  /* for Count Visitor */
    void (*VisitLeaf)(struct Visitor* v ,struct Component* c);
    void (*VisitComposite)(struct Visitor* v ,struct Component* c);
    void (*Print)(struct Visitor* v);
};
void DumpVisitor_VisitLeaf(struct Visitor* pthis ,struct Component* c);
void DumpVisitor_VisitComposite(struct Visitor* pthis ,struct Component* c);
void CountVisitor_VisitLeaf(struct Visitor* pthis ,struct Component* c);
void CountVisitor_VisitComposite(struct Visitor* pthis ,struct Component* c);
void Visitor_Print(struct Visitor* pthis);

/* ComponentList Implementation */
struct ComponentList* New_ComponentList(struct Component* component) {
    struct ComponentList* list = NULL;
    list = (struct ComponentList*)malloc(sizeof(struct ComponentList));
    list->component_ = component;
    list->next_ = NULL;
    return list;
}

void Delete_ComponentList(struct ComponentList* list) {
    free(list);
    list = NULL;
    return;
}


/* Component Class Implementation */
struct Component* New_Component(enum COMPONENT_TYPE type) {
    struct Component* component = NULL;
    component = (struct Component*)malloc(sizeof(struct Component));
    component->type_ = type;
    component->child_top_ = NULL;
    component->child_last_ = NULL;
    switch (type) {
    case LEAF:
        component->accept = &Leaf_accept;
        component->add = &Leaf_add;
        component->Operation = &Leaf_Operation;
        break;
    case COMPOSITE:
        component->accept = &Composite_accept;
        component->add = &Composite_add;
        component->Operation = &Composite_Operation;
        break;
    }
    return component;
}

void Delete_Component(struct Component* component) {
    struct ComponentList* cur = NULL;
    struct ComponentList* tmp = NULL;
    if (component->type_ == COMPOSITE) {
        cur = component->child_top_;
        while (cur != NULL) {
            tmp = cur->next_;
            Delete_Component(cur->component_);
            Delete_ComponentList(cur);
            cur = tmp;
        }
    }
    Delete_Component(component);
    return;
}

void Leaf_accept (struct Component* pthis ,struct Visitor* v) {
    v->VisitLeaf(v ,pthis);
}

void Leaf_add(struct Component* pthis ,struct Component* child) {
    return; /* No operation */
}

void Leaf_Operation(struct Component* pthis ,int n) {
    indent(n);
    printf("- Leaf\n");
    return;
}

void Composite_accept(struct Component* pthis ,struct Visitor* v) {
    struct ComponentList* cur = NULL;
    struct Component* component = NULL;
    v->VisitComposite(v, pthis);
    cur = pthis->child_top_;
    while (cur != NULL) {
        component = cur->component_;
        component->accept(component ,v);
        cur = cur->next_;
    }
    return;
}

void Composite_add(struct Component* pthis ,struct Component* child) {
    struct Component* cur = NULL;
    struct ComponentList* list = NULL;
    list = New_ComponentList(child);
    if (pthis->child_top_ == NULL) {
        pthis->child_top_ = list;
        pthis->child_last_ = list;
    } else {
        pthis->child_last_->next_ = list;
        pthis->child_last_ = list;
    }
    return;
}

void Composite_Operation(struct Component* pthis ,int n) {
    struct Component* component = NULL;
    struct ComponentList* cur = NULL;
    indent(n);
    printf("+ Composite\n");
    cur = pthis->child_top_;
    while (cur != NULL) {
        ++n;
        component = cur->component_;
        component->Operation(component ,n);
        --n;
        cur = cur->next_;
    }
    return;
}


/* Visitor Class Implementation */
struct Visitor* New_Visitor(enum VISITOR_TYPE type) {
    struct Visitor* visitor = NULL;
    visitor = (struct Visitor*)malloc(sizeof(struct Visitor));
    visitor->depth_ = 0;
    visitor->leaf_count_ = 0;
    visitor->comp_count_ = 0;
    switch (type) {
    case DUMP:
        visitor->VisitLeaf = &DumpVisitor_VisitLeaf;
        visitor->VisitComposite = &DumpVisitor_VisitComposite;
        visitor->Print = &Visitor_Print;
        break;
    case COUNT:
        visitor->VisitLeaf = &CountVisitor_VisitLeaf;
        visitor->VisitComposite = &CountVisitor_VisitComposite;
        visitor->Print = &Visitor_Print;
        break;
    }
    return visitor;
}

void Delete_Visitor(struct Visitor* v) {
    free(v);
    v = NULL;
    return;
}

void DumpVisitor_VisitLeaf(struct Visitor* pthis ,struct Component* c) {
    int i = 0;
    for (; i < pthis->depth_; ++i) {
        printf("    ");
    }
    printf("- Leaf\n");
    return;
}

void DumpVisitor_VisitComposite (struct Visitor* pthis ,struct Component* c) {
    int i = 0;
    for (; i < pthis->depth_; ++i) {
        printf("    ");
    }
    printf("+ Composite\n");
    ++pthis->depth_;
    return;
}

void Visitor_Print (struct Visitor* pthis) {
    printf("Leaf: %d\n" ,pthis->leaf_count_);
    printf("Composite: %d\n" ,pthis->comp_count_);
    return;
}


void CountVisitor_VisitLeaf(struct Visitor* pthis ,struct Component* c) {
    ++(pthis->leaf_count_);
    return;
}

void CountVisitor_VisitComposite(struct Visitor* pthis ,struct Component* c) {
    ++(pthis->comp_count_);
    return;
}

void indent(int n) {
    while (n != 0) {
        printf("    ");
        --n;
    }
    return;
}

struct Component* makeComposite() {
    /* 以下のような構造を作る  
     *   Composite -+- Leaf
     *              +- Leaf
     *              +- Composite -+- Leaf
     *                            +- Leaf */ 
    struct Component* composite1 = NULL;
    struct Component* composite2 = NULL;

    composite1 = New_Component(COMPOSITE);
    composite1->add(composite1 ,New_Component(LEAF));
    composite1->add(composite1 ,New_Component(LEAF));

    composite2 = New_Component(COMPOSITE);
    composite2->add(composite2 ,New_Component(LEAF));
    composite2->add(composite2 ,New_Component(LEAF));
    composite2->add(composite2 ,composite1);
    return composite2;

}

int main() {
    struct Component* component = NULL;
    struct Visitor* dumper = NULL;
    struct Visitor* counter = NULL;

    component = makeComposite();

    dumper = New_Visitor(DUMP);
    counter = New_Visitor(COUNT);

    printf("****************************\n");
    component->accept(component ,dumper);
    component->accept(component ,counter);

    printf("****************************\n");
    counter->Print(counter);

    Delete_Visitor(dumper);
    Delete_Visitor(counter);

    return 0;
}


改訂履歴

2005.2.25 デザインパターンの塗り薬へのリンクを追加
  2009.2.28 C言語版の追加
     

ご意見、ご感想はこちらまで。

Copyright(C) 2000-2005 Yoshinori Oota All rights reserved.

本ホームページのリンクは自由です。複製、転載される場合は、必ず著者までご連絡をください。