さて、前回のエントリにてかずくんさんより、
あと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でやってみようと思います。