まさるblog

越後在住アプリケーションエンジニア奮闘記

目次

Blog 利用状況

ニュース

07/04/23
新規加入しました。
よろしくお願いします。

07/06/02
東京勉強会#8に参加しました。

07/10/21
情報処理技術者試験(NW)受験しました。

07/11/17
オブジェクト指向分科会#2参加しました。

07/12/06
SOFTWARE TOYBOXオープンしました。

08/03/02
息子誕生しました。

08/03/05
twitterはじめました。

現在
子育て奮闘中です。
デザインパターン勉強中です。
iKnow!、ESLPodcastなどで英語勉強中です。

ブログパーツ

あわせて読みたい

書庫

日記カテゴリ

コミュニティ

色々

デザインパターンを学ぶ~その7:Decoratorパターン(2)~

さて、前回のエントリにてかずくんさんより、

あとDecoratorパターンは、拡張する方向だけでなく、絞込みにも使えます(Filter)

とコメントいただいたので、今回はDecoratorを使ってFilter処理を行ってみましょう。

 

  1. まず、以下の列挙体とクラスを定義します。
    C# Code
    // 性別列挙体
    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);
        }
    }
    
  2. 次に抽象フィルタクラスを定義します。
    C# Code
    // 抽象フィルタ
    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();
        }
    }
    
  3. 抽象フィルタクラスを定義し、内部にEmployeeクラスのリストを持つHogeCorpクラスを定義します。
    C# Code
    // Hoge会社
    class HogeCorp : AbstractFilter
    {
        // 社員リスト
        protected List<Employee> employees;
    
        public HogeCorp(List<Employee> employees)
        {
            this.employees = employees;
        }
    
        public override List<Employee> GetEmployees()
        {
            return this.employees;
        }
    }
    
  4. 年齢でフィルタリングするための、AgeFilterクラスを定義します。
    C# Code
    // 年齢フィルタ
    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 );
                }
            );
        }
    }
    
  5. 性別でフィルタリングするための、SexFilterクラスを定義します。
    C# Code
    // 性別フィルタ
    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です。早速実行してみましょう。

 

実行用コード

C# Code
class Program
{
    static void Main(string[] args)
    {
        // Hoge会社のインスタンス生成
        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でやってみようと思います。

投稿日時 : 2007年6月12日 0:13

Feedback

# re: デザインパターンを学ぶ~その7:Decoratorパターン(2)~ 2007/06/16 11:15 けろ

はじめまして。あまりにわかりやすく書かれていたので
コメントさせて頂きました。

Decoratorパターンですか。初めて知りました。
見やすくてわかりやすいですね^^ 気に入りました。

2.0になってから、この手のものは、Predicateデリゲート
(http://msdn2.microsoft.com/ja-jp/library/bfcke1bz(VS.80).aspx)

でもできるんですが、考え方が素直じゃないので、
初心者さんたちには、少しつらいんですよね。

今後、参考にさせて頂きます。

# re: デザインパターンを学ぶ~その7:Decoratorパターン(2)~ 2007/06/16 11:52 まさる

>けろさん
はじめまして。

>あまりにわかりやすく書かれていたので
そう言っていただけるとありがたいです。
今後もそういってもらえるよう、がんばります^^

# re: デザインパターンを学ぶ~その7:Decoratorパターン(2)~ 2007/06/16 14:30 けろ

よく見たら、「GetEmployees().FindAll」
としているので、Predicateデリゲートは、
匿名メソッドとして使われていたんですね。
見逃してました。
C#の人には、とてもわかりやすいと思います。

VB.NETの場合は、匿名メソッドが使えないので、
FindAllする時(Predicateデリゲートを作る時)は、
比較用するメソッドを明示的に用意してあげる
必要がありそうですね。
なので、VB.NETにこのサンプルを置き換える時は、
少し注意が必要かもって思いました。

# デザインパターンを学ぶ~その8:Decoratorパターン(3)~ 2007/06/18 0:09 まさるblog

デザインパターンを学ぶ~その8:Decoratorパターン(3)~

# デザインパターンを学ぶ~その11:ちょっとだけDecoratorパターン(1)~ 2007/08/17 14:34 まさるblog

デザインパターンを学ぶ~その11:ちょっとだけDecoratorパターン(1)~

タイトル  
名前  
Url
コメント