倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

「GoF デザインパターン」アノテーション (23) : Visitor パターン

さぁ、ラストの Visitor パターン一覧)。

Visitor パターンの登場人物

  • @Visitor → 型
    • elementType : Class<?>
    • @Visit → メソッド
  • @ConcreteVisitor → 具象クラス
    • visitorType : Class<?>
  • @Element → 型
    • visitorType : Class<?>
    • @Accept → メソッド
  • @ConcreteElement → 具象クラス
    • elementType : Class<?>
  • @ObjectStructure → 型
    • elementType : Class<?>

アノテーション定義


上記の定義の具体的な Java コード。

package org.waman.tools.design.gof.behavioral;

import java.lang.annotation.*;

public final class VisitorPattern {
    
    private VisitorPattern(){}

    @Target(ElementType.TYPE)
    public static @interface Element{

        Class<?> visitorType() default Void.class;

        @Inherited @Target(ElementType.METHOD)
        public static @interface Accept{}
    }

    @Target(ElementType.TYPE)
    public static @interface ConcreteElement{
        Class<?> elementType() default Void.class;
    }

    @Target(ElementType.TYPE)
    public static @interface ObjectStructure{
        Class<?> elementType() default Void.class;
    }

    @Target(ElementType.TYPE)
    public static @interface Visitor{

        Class<?> elementType() default Void.class;

        @Inherited @Target(ElementType.METHOD)
        public static @interface Visit{}
    }

    @Target(ElementType.TYPE)
    public static @interface ConcreteVisitor{
        Class<?> visitorType() default Void.class;
    }
}

サンプルコード in 『Java 言語で学ぶデザインパターン入門』


Element.java

@Element 役のインターフェース。

import org.waman.tools.design.gof.behavioral.VisitorPattern;
import org.waman.tools.design.gof.behavioral.VisitorPattern.Element.Accept;

@VisitorPattern.Element(visitorType = Visitor.class)
public interface Element {
    @Accept public abstract void accept(Visitor v);
}

Entry.java, File.java, Directory.java

import java.util.Iterator;

public abstract class Entry implements Element {
    ...
}
import org.waman.tools.design.gof.behavioral.VisitorPattern;

@VisitorPattern.ConcreteElement(elementType = Element.class)
public class File extends Entry {
    ...
    @Override public void accept(Visitor v) {
        v.visit(this);
    }
}
import java.util.*;

import org.waman.tools.design.gof.behavioral.VisitorPattern;

@VisitorPattern.ConcreteElement(elementType = Element.class)
@VisitorPattern.ObjectStructure(elementType = Element.class)
public class Directory extends Entry implements Iterable<Entry> {
    ...
    @Override public Iterator<Entry> iterator() {...}

    @Override public void accept(Visitor v) {
        v.visit(this);
    }
}

Directory クラスは @Element 役と @ObjectStructure 役の二役。

Visitor.java

@Visitor 役のクラス。

import org.waman.tools.design.gof.behavioral.VisitorPattern;
import org.waman.tools.design.gof.behavioral.VisitorPattern.Visitor.Visit;

@VisitorPattern.Visitor(elementType = Entry.class)
public abstract class Visitor {
    @Visit public abstract void visit(File file);
    @Visit public abstract void visit(Directory directory);
}

ListVisitor.java

@ConcreteVisitor 役のクラス。

@VisitorPattern.ConcreteVisitor(visitorType = Visitor.class)
public class ListVisitor extends Visitor {
    
    private String currentdir = "";
    
    @Override public void visit(File file) {
        System.out.println(currentdir + "/" + file);
    }
    
    @Override public void visit(Directory directory) {
        System.out.println(currentdir + "/" + directory);
        String savedir = currentdir;
        currentdir = currentdir + "/" + directory.getName();

        for(Entry entry: directory)
            entry.accept(this);
        
        currentdir = savedir;
    }
}

増補改訂版Java言語で学ぶデザインパターン入門 オブジェクト指向における再利用のためのデザインパターン Code Complete第2版〈上〉―完全なプログラミングを目指して Code Complete第2版〈下〉―完全なプログラミングを目指して