テンプレートメソッドパターン
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 97/110。
Template Method パターンは、アルゴリズムのスケルトンを基底クラスで定義し、全体の構造を変えることなく、特定のステップをサブクラスでオーバーライドできるようにします。基底クラスがワークフローを制御し、サブクラスが個々のステップをカスタマイズします。
このパターンは継承を使用します。抽象クラスが、一連のステップを呼び出すテンプレートメソッドを定義します。それらのステップのうち、いくつかは抽象的(サブクラスで実装する必要がある)であり、いくつかはデフォルトの実装を持っています:
abstract class DataProcessor {
// テンプレートメソッド - アルゴリズムの構造を定義します
void process() {
readData();
processData();
saveData();
}
void readData(); // 抽象メソッド - サブクラスで実装する必要があります
void processData(); // 抽象メソッド - サブクラスで実装する必要があります
void saveData() { // デフォルトの実装
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
void main() {
var csv = CsvProcessor();
csv.process();
// Reading CSV file
// Parsing CSV rows
// Data saved to database
var json = JsonProcessor();
json.process();
// Reading JSON file
// Parsing JSON objects
// Saved to cloud storage
}process() メソッドはテンプレートであり、操作の順序を定義します。サブクラスは readData() と processData() をそれぞれ異なる方法で実装し、必要に応じて saveData() をオーバーライドできます。主な利点は、個々のステップに柔軟性を持たせながら、アルゴリズムの構造をすべての実装で一貫して維持できることです。
チャレンジ
簡単Template Method パターンを使用して、レポート生成システムを構築しましょう!異なる種類のレポートが同じ全体的な構造に従いながら、各レポートタイプがデータの収集や出力のフォーマットといった特定のステップをカスタマイズできるフレームワークを作成します。
コードを2つのファイルに整理します:
report_generator.dart: このファイルには、抽象基底クラスと具体的なレポートの実装が含まれます。抽象クラスReportGeneratorを作成し、generate()というテンプレートメソッドを定義します。このメソッドは、レポート生成のワークフローをfetchData()、analyzeData()、formatReport()、deliver()の順序で定義します。fetchData()とformatReport()メソッドは抽象メソッド(各レポートタイプで処理が異なるため)とし、analyzeData()はAnalyzing data...を、deliver()はReport delivered via email.をデフォルトの実装として出力するようにします。 次に、2つの具体的なレポートクラスを作成します:SalesReport-fetchData()はFetching sales data from database...を出力し、formatReport()はFormatting as bar charts and tables.を出力します。InventoryReport-fetchData()はFetching inventory levels from warehouse...を出力し、formatReport()はFormatting as inventory list.を出力します。また、deliver()をオーバーライドしてReport sent to warehouse manager.を出力するようにします。
main.dart: レポートジェネレーターのファイルをインポートし、Template Method パターンがアルゴリズムの構造を一定に保ちながらカスタマイズを可能にする様子を実演します。SalesReportを作成し、そのgenerate()メソッドを呼び出します。その後、区切りのために空行を出力します。同様にInventoryReportを作成し、そのgenerate()メソッドを呼び出します。
両方のレポートが同じ4つのステップのプロセスに従いながら、それぞれの目的に応じて重要なステップをカスタマイズしていることに注目してください。InventoryReport では、デフォルトの配信方法をオーバーライドして、別の宛先にレポートを送信するようにしています!
期待される出力:
Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.
Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.チートシート
Template Method パターンは、アルゴリズムのスケルトンを基底クラスで定義し、全体の構造を変えることなく、サブクラスが特定のステップをオーバーライドできるようにします。
抽象クラスは、一連のステップを呼び出すテンプレートメソッドを定義します。一部のステップは抽象的(サブクラスで実装する必要がある)であり、一部にはデフォルトの実装があります:
abstract class DataProcessor {
// テンプレートメソッド - アルゴリズムの構造を定義します
void process() {
readData();
processData();
saveData();
}
void readData(); // 抽象的 - サブクラスで実装する必要があります
void processData(); // 抽象的 - サブクラスで実装する必要があります
void saveData() { // デフォルトの実装
print('Data saved to database');
}
}
class CsvProcessor extends DataProcessor {
@override
void readData() => print('Reading CSV file');
@override
void processData() => print('Parsing CSV rows');
}
class JsonProcessor extends DataProcessor {
@override
void readData() => print('Reading JSON file');
@override
void processData() => print('Parsing JSON objects');
@override
void saveData() => print('Saved to cloud storage');
}
テンプレートメソッドはワークフローの順序を制御します。サブクラスは、抽象メソッドを実装し、オプションでデフォルトの実装をオーバーライドすることで、個々のステップをカスタマイズします。アルゴリズムの構造は、すべての実装において一貫性を保ちます。
自分で試してみよう
import 'report_generator.dart';
void main() {
// TODO: SalesReport を作成し、その generate() メソッドを呼び出す
// TODO: 区切りのために空行を出力する
// TODO: InventoryReport を作成し、その generate() メソッドを呼び出す
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4Null Safety
Null Safety 入門Nullable と Non-Nullable? 演算子と ! 演算子late キーワードと Null SafetyNull-Aware 演算子クラスにおける Null Safetyまとめ:ユーザープロフィールシステム10コレクションとジェネリクス
List, Set, Map の概要型安全なコレクションジェネリッククラスジェネリックメソッドジェネリクスの制約Iterable と Iteratorまとめ:ジェネリックなストレージ