Menu
Coddy logo textTech

テンプレートメソッドパターン

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 59/70。

Template Methodパターンは、base classでalgorithmの骨格を定義し、全体の構造を変更せずにsubclassが特定の手順をoverrideできるようにする振る舞いパターンです。base classがワークフローを制御し、derived classが個々の部分をカスタマイズします。

このパターンは継承とabstract methodを使用します。base classには、ステップのシーケンスを呼び出す「template method」が含まれており、その一部はabstractで、subclassによって実装されなければなりません。

public abstract class DataProcessor
{
    // テンプレートメソッド - アルゴリズムの構造を定義する
    public void Process()
    {
        ReadData();
        ProcessData();
        SaveData();
    }
    
    protected abstract void ReadData();
    protected abstract void ProcessData();
    protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}

public class CsvProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading CSV file");
    protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}

public class JsonProcessor : DataProcessor
{
    protected override void ReadData() => Console.WriteLine("Reading JSON file");
    protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
    protected override void SaveData() => Console.WriteLine("Saving to cloud");
}

各サブクラスは独自の implementation を提供し、base class は操作の order を強制します:

DataProcessor csv = new CsvProcessor();
csv.Process();
// CSVファイルの読み込み
// CSVデータの解析
// Saving to default location

DataProcessor json = new JsonProcessor();
json.Process();
// JSONファイルの読み込み
// JSONデータの解析
// クラウドへの保存

Template Method パターンは、複数のクラスが同じ algorithm 構造を共有しながら、特定のステップが異なる場合に最適です。共通ロジックを base クラスに配置しつつ、オーバーライド可能な method によって柔軟性を実現することで、コードの再利用を促進します。

challenge icon

チャレンジ

簡単

Template Method パターンを使用して report 生成システムを構築しましょう。異なる種類の report(sales report や inventory report など)は、全体的な構造を共有しています。つまり、どの report も data を GatherData し、FormatReport して、結果を OutputReport する必要がありますが、各 report の種類によってこれらの手順の処理方法は異なります。

コードを3つのファイルに分けて整理します。

  • ReportGenerator.cs: Reporting namespace に abstract な ReportGenerator class を Create します。この base class は、Generate() という template method を通じて report 生成 algorithm の骨格を定義します。この method は、GatherData()FormatReport()OutputReport() の3つの手順をこの order で call する必要があります。GatherData()FormatReport() は abstract にし(各 report type が異なる方法で implementation します)、OutputReport() は、Sending to default printer を print する default implementation を持つ virtual method にします。
  • ConcreteReports.cs: 同じ namespace に、ReportGenerator を継承する2つの concrete report class を Create します。
    • SalesReport - GatherData() を実装して Collecting sales data from database を print し、FormatReport() を実装して Formatting as sales summary を print します
    • InventoryReport - GatherData() を実装して Scanning warehouse inventory を print し、FormatReport() を実装して Formatting as inventory list を print し、OutputReport() を override して Sending to warehouse manager を print します
  • Program.cs: report instance を Create して Generate することで、すべてを結び付けます。template method により、各 report は同じ3段階の Process に従いますが、各手順の具体的な動作は report type に応じて異なります。

1つの input を受け取ります。

  • report type: sales または inventory

input に基づいて appropriate な report generator を Create し、その Generate() method を call します。

たとえば、input が sales の場合、Output は次のようになります。

Collecting sales data from database
Formatting as sales summary
Sending to default printer

input が inventory の場合、Output は次のようになります。

Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse manager

どちらの report もまったく同じ algorithm structure(GatherData、FormatReport、OutputReport)に従っていますが、各手順の implementation はカスタマイズされていることに注目してください。SalesReport は default の Output 動作を使用する一方、InventoryReport はそれを override します。これは、Template Method パターンによって、どの手順を必ず override する必要があり、どの手順を任意でカスタマイズできるかを制御できることを示しています。

自分で試してみよう

using System;
using Reporting;

class Program
{
    public static void Main(string[] args)
    {
        string reportType = Console.ReadLine();
        
        // TODO: reportType に基づいて適切なレポートジェネレーターを作成する
        // reportType が "sales" の場合、SalesReport を作成する
        // reportType が "inventory" の場合、InventoryReport を作成する
        // その後、レポートの Generate() メソッドを呼び出す
        
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C#オンラインコンパイラ