前回は振りだけでしたが、
今回からデザインパターンとの絡ませ方を紹介してきます。
Strategyパターンの実例
Strategyパターンの実例として
java.lang.Comparator
および
System.Collections.Generic.IComparer
によるソートを取り上げます。
Strategyパターンによって切り替わるのは、ソートのアルゴリズムではなく、二つのオブジェクトの比較方法です。
ここではUserというオブジェクトを想定してみます。
Java
public class User {
public String name;
public int age;
}
このUserのListがあるとして、これを名前(name)順にソートするのか、あるいは年齢(age)順に
ソートするのかといったことをStrategyパターンで切り替えるわけです。
そのためのStrategyのインターフェースが先に挙げた
java.lang.Comparator
および
System.Collections.Generic.IComparer
となるわけです。
これらの実装クラスをStrategyとしてソートのメソッドに渡すことで、ソート処理の動きを切り替えることが出来ているわけです。
Java Strategyの実装
public class UserNameComparator implements Comparator<User> {
public int compare(User user1, User user2) {
return user1.name.compareTo(user2.name);
}
}
Java ソート処理の呼び出し
List<User> list = new ArrayList<User>();
list.add(new User("ABC", 10));
list.add(new User("BCD", 12));
list.add(new User("CDE", 8));
Collections.sort(list, new UserNameComparator());
C# Strategyの実装
public class UserNameComparer : IComparer<User>
{
public int Compare(User user1, User user2)
{
return user1.name.CompareTo(user2);
}
}
C# ソート処理の呼び出し
List<User> list = new List<User>();
list.add(new User("ABC", 10));
list.add(new User("BCD", 12));
list.add(new User("CDE", 8));
list.Sort(new UserNameComparer());
ジェネリクスによる具象化
さて、ここでジェネリクスによる具象化がどこで行われるかを見てみましょう。
まずはソート処理を呼び出す部分。こちらではListに入るオブジェクト型を明示しています。
ここのソースコード状ではジェネリクス型パラメータは具象化されているわけです。
そして呼び出されたソート処理の中身、つまるところクラスライブラリ内では当然ながら
StrategyであるComparatorやIComparerのジェネリクス型は具象化されない状態で処理されます。
ですから、ソートのアルゴリズム中ではListのオブジェクトが何型かを意識してはいけません。
動的にinstanceofとかで調べることはできますが、覗き見はしてはダメ。
そして、実際のStrategyの具象型部分。ここでは比較を行うオブジェクトは具体化されています。
型が具体化されているのでキャストなどは不要で、Listに格納される型に合わせた処理をそのまま記述できます。
キセルのような中抜きの抽象化
ジェネリクスがない場合、Strategyの実装クラスでキャストしなくてはなりません。
事実、ジェネリクス搭載前のJavaではそのようにコードを書かざるを得ませんでした。
ソートのアルゴリズムを抽象化したら、比較のアルゴリズムの引数まで抽象型(Object型)に
なってしまっていたのです。これをジェネリクスによって具象化することができるようになりました。
中間のソートのアルゴリズム中では型は抽象的に、呼び出し部分およびStrategyの実装部分では具体的に
というわがままな抽象化がジェネリクスによって可能となったのです。
投稿日時 : 2008年5月30日 17:59