「JAVA言語で学ぶデザインパターン入門」をC#で書いてみた【Visitorパターン】

「増補改訂版Java言語で学ぶデザインパターン入門」の「Visitorパターン」をC#で書いてみました。

GitHubにもコードを置いています。

参考 DesignPattern【Visitor】GitHub

コード


public abstract class Visitor
{
    public abstract void Visit(File file);
    public abstract void Visit(Directory directory);
}

public interface IElement
{
    abstract void Accept(Visitor v);
}

public abstract class Entry : IElement
{
    public abstract string GetName();
    public abstract int GetSize();
    public abstract Entry Add(Entry entry);
    public abstract IEnumerator< Entry> Iterator();

    public override string ToString()
    {
        return $"{GetName()}({GetSize()})";
    }

    public abstract void Accept(Visitor v);
}

public class File : Entry
{
    private string name;
    private int size;
    public File(string name, int size)
    {
        this.name = name;
        this.size = size;
    }

    public override Entry Add(Entry entry)
    {
        throw new FileTreatmentException();
    }

    public override string GetName()
    {
        return name;
    }

    public override int GetSize()
    {
        return size;
    }

    public override IEnumerator< Entry> Iterator()
    {
        throw new FileTreatmentException();
    }

    public override void Accept(Visitor v)
    {
        v.Visit(this);
    }
}

public class Directory : Entry
{
    private string name;
    private IList< Entry> dir = new List< Entry>();
    public Directory(string name)
    {
        this.name = name;
    }

    public override Entry Add(Entry entry)
    {
        dir.Add(entry);
        return this;
    }

    public override string GetName()
    {
        return name;
    }

    public override int GetSize()
    {
        int size = 0;
        var it = dir.GetEnumerator();
        while (it.MoveNext())
        {
            size += it.Current.GetSize();
        }
        return size;
    }

    public override IEnumerator< Entry> Iterator()
    {
        return dir.GetEnumerator();
    }

    public override void Accept(Visitor v)
    {
        v.Visit(this);
    }

    public override string ToString()
    {
        return $"{GetName()}({GetSize()})";
    }
}

public class ListVisitor : Visitor
{
    private string currentdir = "";

    public override void Visit(File file)
    {
        Console.WriteLine($"{currentdir}/{file}");
    }

    public override void Visit(Directory directory)
    {
        Console.WriteLine($"{currentdir}/{directory}");
        string savefir = currentdir;
        currentdir = $"{currentdir}/{directory.GetName()}";
        var it = directory.Iterator();
        while (it.MoveNext())
        {
            it.Current.Accept(this);
        }
        currentdir = savefir;
    }
}

public class FileTreatmentException : Exception
{
    public FileTreatmentException() : base()
    {
    }

    public FileTreatmentException(string message) : base(message)
    {
    }

    public FileTreatmentException(string message, Exception innerException)
        : base(message, innerException)
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Maling root entries...");
            Directory rootdir = new Directory("root");
            Directory bindir = new Directory("bin");
            Directory tmpdir = new Directory("tmp");
            Directory usrdir = new Directory("usr");
            rootdir.Add(bindir);
            rootdir.Add(tmpdir);
            rootdir.Add(usrdir);
            bindir.Add(new File("vi", 1000));
            bindir.Add(new File("latex", 2000));
            rootdir.Accept(new ListVisitor());

            Console.WriteLine("");
            Console.WriteLine("Making usr entries...");
            Directory yuki = new Directory("yuki");
            Directory hanako = new Directory("hanako");
            Directory tomura = new Directory("tomura");
            usrdir.Add(yuki);
            usrdir.Add(hanako);
            usrdir.Add(tomura);
            yuki.Add(new File("diary.html", 100));
            yuki.Add(new File("Composite.java", 200));
            hanako.Add(new File("memo.tex", 300));
            tomura.Add(new File("game.doc", 400));
            tomura.Add(new File("junc.mail", 500));
            rootdir.Accept(new ListVisitor());
        }
        catch (FileTreatmentException ex)
        {
            Console.WriteLine(ex);
        }
    }
}

実行結果は以下のようになります。

Making root entries...
/root(3000)
/root/bin(3000)
/root/bin/vi(1000)
/root/bin/latex(2000)
/root/tmp(0)
/root/usr(0)

Making usr entries...
/root(4500)
/root/bin(3000)
/root/bin/vi(1000)
/root/bin/latex(2000)
/root/tmp(0)
/root/usr(1500)
/root/usr/yuki(300)
/root/usr/yuki/diary.html(100)
/root/usr/yuki/Composite.java(200)
/root/usr/hanako(300)
/root/usr/hanako/memo.tex(300)
/root/usr/tomura(900)
/root/usr/tomura/game.doc(400)
/root/usr/tomura/junc.mail(500)

その他のデザインパターンは以下の記事から確認してください。

「JAVA言語で学ぶデザインパターン入門」をC#で書いてみた【一覧】

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA