asatoの技術的な日常日記

「成長に最大の責任をもつ者は、本人であって組織ではない。自らと組織を成長させるためには何に集中すべきかを、自らに問わなければならない」  非営利組織の経営 - ピーター・ドラッカー

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

コード進化パターン:抽象クラスの Template Method 化

コード進化パターン」のシリーズ。

今回にパターンは「抽象クラスの Template Method 化」という内容。名前から分かるように、Template Method パターンに関係する内容。

名前付けは、ちょっと間違えた気がするけど。

とりあえず、進化前のコードはこんな感じ:


abstract_class_to_template_method_before.jpg


public abstract class AbstractClass {

public void method() {
System.out.println("AbstractClass.method()");
}

// 単なる抽象メソッド。AbstractClass が抽象クラスであることを
// 表すために定義。進化の観点からは関係なし。
public abstract void abstractMethod();
}
public class ConcreteClass extends AbstractClass {

@Override
public void method() {

super.method(); // ここが重要。

System.out.println("XXX");
}

@Override
public void abstractMethod() {
System.out.println("ConcreteClass.abstractMethod()");
}
}




進化後はこんな感じ:
abstract_class_to_template_method_after.jpg




public abstract class AbstractClass { // AbstractClass のロール

public void method() { // templateMethod のロール

System.out.println("AbstractClass.method()");

primitiveMethod();
}
// primitiveOperation のロール。抽象メソッドでもよい。
protected void primitiveMethod() { }


public abstract void abstractMethod();
}
public class ConcreteClass extends AbstractClass {

// method() はオーバーライドせずに、
// この primitiveMethod() をオーバーライドする。
@Override
protected void primitiveMethod() {
System.out.println("XXX");
}


@Override
public void abstractMethod() {
System.out.println("ConcreteClass.abstractMethod()");
}
}



コードから分かるように、サブクラスでオーバーライドできるように単に primitive メソッドを追加して、template メソッドからそれを呼び出すようにしただけ。

考察


進化の流れから、考察を行ってみたい。前回 ちょっと議論したように、進化のパターンを議論するにあたって重要となりそうな概念の一つに、進化のリクエスタ/プロバイダというのがあると思う。

進化リクエスタ とは、ある構成要素(コンポーネント、あるいはモジュール、クラス)に対して、何らかの構造的変化を要求する構成要素。

進化プロバイダ とは、進化リクエスタからの要求に応じて、自身の構造を変化させる構成要素。

上の「抽象クラスの Template Method 化」の例で言えば、ConcreteClass が進化リクエスタであり、AbstractClass が進化プロバイダとなる。
req_pro.png


図からわかるように、2つのフェーズがあるんじゃないかと思う。名前付けは、悩んだけど、適切ではないかもしれない。
-(1)要求フェーズ:ある構成要素が、他の構成要素に対して、構造的変化を要求するフェーズ。要求する構成要素を、進化リクエスタと呼ぶ。要求に応答する構成要素を、進化プロバイダと呼ぶ。

ここで、要求に答えられない可能性もある。たとえば、外部のライブラリに対しては、変化を要求することは難しい。

-(2)提供フェーズ:進化リクエスタからの要求に答えて、進化プロバイダは、構造を変化させる。

-(3)応答フェーズ:進化プロバイダの構造変化に応答して、進化リクエスタは構造を変化させる。

疑問


いくつかの疑問がある。
-(1)原理・原則との関係:進化リクエスタは、要求を出す、ということを仮定していた。そもそも、その要求はどんな原理・原則に基づいて行われるのか?

GoF 本では、Template Method パターンの適用可能性の一つとして次を挙げている。

サブクラスの拡張を制御する場合。特定の時点で "hook" operation を呼び出すテンプレートメソッドを定義することができる。それにより、このポイントでのみ拡張が許されることになる。


この「抽象クラスの Template Method 化」という進化パターンは、この適用可能性として起こったのか? うまくは答えられないけど、No だと思う。

あるいは別の記述では(太字は僕による):


サブクラスは、オペレーションをオーバーライドしたり、親のオペレーションを明示的に呼び出すことにより、親クラスのオペレーションの振る舞いを拡張することができる。

void DerivedClass::Operation() {
// DerivedClass extended behavior
// ParentClass::Operation();
}

しかし残念なことに、継承したオペレーションを呼び出すことで拡張するということは忘れやすい。そこで、そのようなオペレーションを template method に変換して、サブクラスがそのオペレーションをどのように拡張するのかを親クラスに管理させるようにすることができるのである。その場合、template method から hook operation を呼び出すようにしておき、サブクラスでこの hook operation をオーバーライドする。

~省略~



太字にした部分が、進化の動機になる要素の 一つ だと思う。ただし、この引用文からは、「継承したオペレーションを呼び出すことで拡張するということは忘れやすい。したがって、あらかじめ、メソッドを template method にしておく」というということを感じる。

しかし、あらかじめ、つまり予測して設計することは
-(1)困難
-(2)不適切に複雑
な設計になりうる危険がある。

つまり、Template Method パターンが適用されていない状況(進化前)から、Template Method パターンが適用されている状況(進化後)に導く状況と、その理由が存在すると思う。

-(2)進化関連の種類とパターン:考察の部分で紹介した、進化リクエスタ/プロバイダのやり取りは、一つの種類でしかないと思う。たとえば、
-(1)進化リクエスタが複数ある場合があるかもしれない。
-(2)進化プロバイダは、要求にこたえるために、自身が進化リクエスタとなって他の構成要素になんらかの進化の要求を行うかもしれない。
スポンサーサイト

コメント

承認待ちコメント

このコメントは管理者の承認待ちです

  • 2007/05/19(土) 21:39:46 |
  • |
  • #
  • [ 編集]

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバックURLはこちら
http://asatohan.blog77.fc2.com/tb.php/56-e05bece0
この記事にトラックバックする(FC2ブログユーザー)

FC2Ad

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。