さて、前回のエントリにてかずくんさんより、
  あとDecoratorパターンは、拡張する方向だけでなく、絞込みにも使えます(Filter)
 とコメントいただいたので、今回はDecoratorを使ってFilter処理を行ってみましょう。
  
  - まず、以下の列挙体とクラスを定義します。  
enum Sex
{
    Male,
    Female
}
class Employee
{
    public int Age;
    public Sex Sex;
    public string Name;
    public Employee(int age, Sex sex, string name)
    {
        this.Age = age;
        this.Sex = sex;
        this.Name = name;
    }
    public override string ToString()
    {
        return String.Format("Age:{0}, Sex:{1}, Name:{2}"
            , this.Age, this.Sex, this.Name);
    }
}
 
- 次に抽象フィルタクラスを定義します。 
abstract class AbstractFilter
{
    public abstract List<Employee> GetEmployees();
    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        GetEmployees().ForEach(
            delegate(Employee employee)
            {
                sb.Append("- ");
                sb.Append(employee.ToString());
                sb.Append(Environment.NewLine);
            }
        );
        return sb.ToString();
    }
}
 
- 抽象フィルタクラスを定義し、内部にEmployeeクラスのリストを持つHogeCorpクラスを定義します。 
class HogeCorp : AbstractFilter
{
    
    protected List<Employee> employees;
    public HogeCorp(List<Employee> employees)
    {
        this.employees = employees;
    }
    public override List<Employee> GetEmployees()
    {
        return this.employees;
    }
}
 
- 年齢でフィルタリングするための、AgeFilterクラスを定義します。 
class AgeFilter : AbstractFilter
{
    
    private int minAge;
    
    private int maxAge;
    
    private AbstractFilter abstractFilter;
    public AgeFilter(int minAge, int maxAge, AbstractFilter abstractFilter)
    {
        this.minAge = minAge;
        this.maxAge = maxAge;
        this.abstractFilter = abstractFilter;
    }
    public override List<Employee> GetEmployees()
    {
        return abstractFilter.GetEmployees().FindAll(
            delegate(Employee employee)
            {
                
                return ( minAge <= employee.Age && employee.Age <= maxAge );
            }
        );
    }
}
 
- 性別でフィルタリングするための、SexFilterクラスを定義します。 
class SexFilter : AbstractFilter
{
    
    Sex sex;
    private AbstractFilter abstractFilter;
    public SexFilter(Sex sex, AbstractFilter abstractFilter)
    {
        this.sex = sex;
        this.abstractFilter = abstractFilter;
    }
    public override List<Employee> GetEmployees()
    {
        return abstractFilter.GetEmployees().FindAll(
            delegate(Employee employee)
            {
                
                return ( employee.Sex == this.sex );
            }
        );
    }
}
 
これで準備はOKです。早速実行してみましょう。
 
実行用コード
class Program
{
    static void Main(string[] args)
    {
        
        HogeCorp hogeCorp = new HogeCorp(
            new List<Employee>(
                new Employee[] {
                    new Employee(18,    Sex.Male,    "太郎")
                    ,new Employee(25,    Sex.Female,    "幸子")
                    ,new Employee(22,    Sex.Male,    "浩二")
                    ,new Employee(35,    Sex.Female,    "茜")
                    ,new Employee(30,    Sex.Female,    "葉月")
                    ,new Employee(27,    Sex.Male,    "智")
                }
            )
        );
        Console.WriteLine("■全社員");
        Console.WriteLine(hogeCorp);
        Console.WriteLine("■性別男性でフィルタリング");
        SexFilter sexFilter = new SexFilter(Sex.Male, hogeCorp);
        Console.WriteLine(sexFilter);
        Console.WriteLine("■20歳以上、30歳以下でフィルタリング");
        AgeFilter ageFilter = new AgeFilter(20, 30, sexFilter);
        Console.WriteLine(ageFilter);
        Console.ReadLine();
    }
}
実行結果
■全社員
- Age:18, Sex:Male, Name:太郎
- Age:25, Sex:Female, Name:幸子
- Age:22, Sex:Male, Name:浩二
- Age:35, Sex:Female, Name:茜
- Age:30, Sex:Female, Name:葉月
- Age:27, Sex:Male, Name:智
■性別男性でフィルタリング
- Age:18, Sex:Male, Name:太郎
- Age:22, Sex:Male, Name:浩二
- Age:27, Sex:Male, Name:智
■20歳以上、30歳以下でフィルタリング
- Age:22, Sex:Male, Name:浩二
- Age:27, Sex:Male, Name:智
こんな感じで、見事にフィルタリングされた結果が出力されました。でも、順番を逆にしてもしっかりフィルタリングされなければ、Decoratorの意味がありませんよね。ってことでやってみるとこんな感じ。
実行結果 その2
■全社員
- Age:18, Sex:Male, Name:太郎
- Age:25, Sex:Female, Name:幸子
- Age:22, Sex:Male, Name:浩二
- Age:35, Sex:Female, Name:茜
- Age:30, Sex:Female, Name:葉月
- Age:27, Sex:Male, Name:智
■20歳以上、30歳以下でフィルタリング
- Age:25, Sex:Female, Name:幸子
- Age:22, Sex:Male, Name:浩二
- Age:30, Sex:Female, Name:葉月
- Age:27, Sex:Male, Name:智
■性別男性でフィルタリング
- Age:22, Sex:Male, Name:浩二
- Age:27, Sex:Male, Name:智
問題ありませんね。どうやら無事にできたようです。
 
というわけで、今回はDecoratorを使ってFilter処理やってみましたが、この程度だったらこないだの東京勉強会#8でεπιστημηさんがやってた、IEnumerable<T>を使ったやり方のほうが汎用的だし、簡単かも。(ビデオまだかなー^^)
でも、ある程度決まったパターンを今回みたいにクラス化しておけば、初心者、初級者さんたちには使いやすいかな?
 
さて、次回はかずくんさんからの、もう一つの課題「Pipe」をDecoratorでやってみようと思います。