2011年11月30日水曜日

( デザインパターン )イテレータパターン

今回はイテレータパターン。
独習デザインパターン ではJavaですが、C#で書きます。
このパターンの目的は
「集約オブジェクト内の個々のオブジェクトに統一化された手段でアクセスできるようにするためのパターン」
だそうです。
本には例として社員名簿一覧を表示する場合があげられています。一人分の社員情報を保持するEmployeeクラスを作り、これを使ってあらかじめ社員の名前と住所を登録して名簿を作成するというもの。
うだうだうんちく書くよりコード書くほうが理解しやすいので以下コード

public class Employee
{
    private string name;
    private string address;
    public Employee(string name, string address)
    {
        this.name = name;
        this.address = address;
    }

    public string getName()
    {
        return name;
    }

    public string getAddress()
    {
        return address;
    }
}

public interface Aggregate
{
    Iterator iterator();
}

public interface Iterator
{
    bool hasNext();
    object next();
}

public class IteratorOffice : Iterator
{
    private Office office;
    private int cursor;

    public  IteratorOffice(Office office)
    {
        this.office = office;
        this.cursor = 0;
    }

    public Office Office
    {
        get
        {
            throw new System.NotImplementedException();
        }
        set
        {
        }
    }

    public bool hasNext()
    {
        if(cursor < office.size())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public object next()
    {
        object employee = office.get(cursor);
        cursor++;
        return employee;
    }
}

public class Office : Aggregate
{
    private List<object> employees;

    public Office(int max)
    {
        employees = new List<object>(max);
    }

    public IteratorOffice IteratorOffice
    {
        get
        {
            throw new System.NotImplementedException();
        }
        set
        {
        }
    }

    public Employee Employee
    {
        get
        {
            throw new System.NotImplementedException();
        }
        set
        {
        }
    }

    public void add(object obj)
    {
        employees.Add(obj);
    }

    public object get(int index)
    {
        return employees[index];
    }

    public int size()
    {
        return employees.Count;
    }

    public Iterator iterator()
    {
        return new IteratorOffice(this);
    }
}

書いていて気付いたのだが、C#ではインターフェイスの中でabstructが使えないようだ。C#の場合

interface I 
{
    void M();
}
abstract class C: I 
{
    public abstract void M();
}
(MSDNより)
のように書けば書籍と同じようになるのだろう。今回は却下。(めんどい)

話しを戻します。上記プログラムを使う場合は 
 


Office office = new Office(3);

office.add(new Employee("山田", "神奈川"));

office.add(new Employee("土田", "香川"));

office.add(new Employee("木田", "東京"));

Iterator iter = office.iterator();

string temp = "";

while (iter.hasNext())

{
    Employee employee = (Employee)iter.next();
    temp += employee.getName() + " : " + employee.getAddress() + "\n";

}

MessageBox.Show(temp);

 

のようにする。このプログラムでは最後にメッセージボックスに名簿リストが表示されます。 
 
それでこのパターンを適用するとどうなるかというと
①Iteratorオブジェからの取得方法統一化。内部構造を考えず、常に決まった取り出しが可能
②集約オブジェの変更があってもIteratorオブジェを仲介するので取得側コード変更不要。
③Iteratorクラスのサブクラスを定義することで、様々な走査方法を実現できる。(*1)
というメリットがあるそうです。


なんとなくわかったようなわからんような...。今のところこのパターンを適用したいと思うアプリは思いつかないなぁ...。

(*1)今回はこのメリットは見られない。