連載
.NETで始めるデザインパターン

第4回 リファクタリングにより導き出すTemplate Methodパターン

太陽システム株式会社 中西 庸文
Microsoft MVP 2005 - Solutions Architect)
2005/04/23
Page1 Page2 Page3 Page4


Back Issue
1
.NET開発におけるデザインパターンの有用性
2
うまくデザインパターンを使うための心得
3
リファクタリングにより導き出すStrategyパターン
4
リファクタリングにより導き出すTemplate Methodパターン
5
Compositeパターンを導き出すための準備
6
リファクタリングにより導き出すCompositeパターン
7
デザインパターンの落とし穴

 前回は、XP(エクストリーム・プログラミング)の「5つの価値」の内容(コミュニケーション、シンプル、フィードバック、勇気、敬意)をプレーン・テキスト形式やHTML形式で出力できるサンプル・プログラムを作成し、それをリファクタリングすることでStrategyパターンを導き出した。このリファクタリングは「Replace Conditional Logic with Strategy(K)」(Strategyパターンによる条件ロジックの置き換え)と呼ばれると紹介した。

 今回は、前回のサンプル・プログラムに対してさらにリファクタリングを加えていく。実は前回までのリファクタリングは、今回行うリファクタリングのための布石にすぎなかったのだ。引き続きリファクタリングを行って、さらなるデザインパターンを導いていくことにしよう。

 なお本稿の開発手順は、すべてテスト駆動開発(TDD:Test-Driven Development)のスタイルで行う(テスト駆動開発については、「テスト駆動開発ツール最前線」を参照されたい)。前回同様、本稿のサンプル・コードは、追加したコードは青色、削除したコードは赤色で表現している。

■リファクタリング前の設計

 まず、現状のStrategyパターン部分のコード(抽象クラスであるTextFormatterクラスと、その派生クラスであるPlainTextFormatterクラスとHtmlTextFormatterクラス)を以下に再掲する。

 今回のリファクタリングでは、これら以外のテスト・コードおよびXpValuesクラスには変更を加えないので割愛する。これについては前回のコードを参照いただきたい。

using System;

namespace DesignPatterns.Core.TemplateMethod
{
  // TextFormatterクラス
  public abstract class TextFormatter
  {
    // 「価値」を出力する
    public abstract string Format(XpValues xpValues);

    // タイトルを取得する
    protected string GetTitleFor(XpValues xpValues)
    {
      return xpValues.Name + "の" + xpValues.Count.ToString() + "つの価値";
    }
  }
}
TextFormatterクラス(C#)
 
using System;
using System.Text;

namespace DesignPatterns.Core.TemplateMethod
{
  // PlainTextFormatterクラス
  public class PlainTextFormatter : TextFormatter
  {
    // 「価値」を出力する
    public override string Format(XpValues xpValues)
    {
      StringBuilder builder = new StringBuilder();
      builder.Append(GetTitleFor(xpValues) + "\r\n");
      foreach (string xpValue in xpValues)
        builder.Append("・" + xpValue + "\r\n");
      return builder.ToString();
    }
  }
}
PlainTextFormatterクラス(C#)
 
using System;
using System.Text;

namespace DesignPatterns.Core.TemplateMethod
{
  // HtmlTextFormatterクラス
  public class HtmlTextFormatter : TextFormatter
  {
    // 「価値」を出力する
    public override string Format(XpValues xpValues)
    {
      StringBuilder builder = new StringBuilder();
      builder.Append("<p>" + GetTitleFor(xpValues) + "</p>\r\n");
      builder.Append("<ul>\r\n");
      foreach (string xpValue in xpValues)
        builder.Append("<li>" + xpValue + "\r\n");
      builder.Append("</ul>\r\n");
      return builder.ToString();
    }
  }
}
HtmlTextFormatterクラス(C#)

 ここまでのコードは、プレーン・テキスト形式の出力アルゴリズム(=Strategy:戦略)をPlainTextFormatterクラスに、HTML形式の出力アルゴリズムをHtmlTextFormatterクラスに、それぞれカプセル化しておき、利用者にはポリモーフィズムにより、これらの基本クラスであるTextFormatterクラスのみを通じて各出力アルゴリズムを使用させるというStrategyパターンになっている。

■リファクタリングから Template Method パターンへ

 前回のリファクタリングの結果としてStrategyパターンが導かれた。しかし、これらのコードには重複するアルゴリズムが存在している。以降のリファクタリングでは、この重複するアルゴリズムを除去していくことにしよう。

●Template Methodの形成

 PlainTextFormatterクラスのFormatメソッドと、HtmlTextFormatterクラスのFormatメソッドに注目してほしい。これらのメソッドを比較してみると、次のように、テキストの各パートを順番に出力するという点において、アルゴリズムが非常に似ていることに気付くだろう。

  • HtmlTextFormatterクラスのFormatメソッド
    • タイトルの出力
    • ヘッダの出力
    • 価値の出力
    • フッタの出力
  • PlainTextFormatterクラスのFormatメソッド
    • タイトルの出力
    • 価値の出力

 PlainTextFormatterクラスのFormatメソッドには、「ヘッダの出力」および「フッタの出力」が必要ないだけで、そのアルゴリズムはHtmlTextFormatterクラスのFormatメソッドと重複していると見なすことができる。

 このような重複するアルゴリズムをそのままにしておけば、新しい形式で「価値」を出力するようなTextFormatterクラスの派生クラスを追加した際には、同じようなアルゴリズムのコードがさらに増えることになる。

 そこで、基本クラスであるTextFormatterクラスでは、XPの価値を出力するための各ステップをそれぞれ個別のメソッドとして定義し、Formatメソッドでそれらのメソッドを呼び出すようにする。また、出力形式によって振る舞いの異なるメソッドは抽象メソッドにし、派生クラスでその振る舞いをオーバーライドできるようにする。

 このようにすれば、アルゴリズムの骨組みとなる固定部分は基本クラス側で共通化され、可変部分は派生クラス側で拡張できる。コードの重複はなくなり、新しい出力形式への対応も容易になるはずだ。

 これは「Template Methodパターン」の目的と一致する。書籍『オブジェクト指向における再利用のためのデザインパターン』では、Template Methodパターンの目的は次のように記述されている。

1つのオペレーションにアルゴリズムのスケルトンを定義しておき、その中のいくつかのステップについては、サブクラスでの定義に任せることにする。Templete Methodパターンでは、アルゴリズムの構造を変えずに、アルゴリズム中のあるステップをサブクラスで再定義する。

 「Template Method」とは、その名のとおりアルゴリズムの骨組みを定義したメソッドのことだ。

 それでは、重複したアルゴリズムからTemplate Methodパターンを導くためのリファクタリングの手順を紹介しよう。


 INDEX
  .NETで始めるデザインパターン
  第4回 リファクタリングにより導き出すTemplate Methodパターン
  1.リファクタリングから Template Method パターンへ
    2.リファクタリング:「Compose Method(K)」
    3.リファクタリング:「メソッドの引き上げ(F)」
    4.リファクタリングの結果
 
インデックス・ページヘ  「.NETで始めるデザインパターン」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間