テンプレートメソッドパターン
CoddyのDartジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 97/110。
Template Method パターンは、base class で algorithm の骨格を定義し、全体の構造を変更せずに subclass が特定のステップをオーバーライドできるようにします。base class がワークフローを制御し、subclass が個々のステップをカスタマイズします。
このパターンは継承を使用します。abstract class は、手順のシーケンスを呼び出すテンプレートメソッドを defines します。その手順の一部は abstract(サブクラスによって実装される必要があります)であり、残りにはデフォルト実装があります。
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();
// CSVファイルを読み取り中
// CSV行を解析中
// データをデータベースに保存しました
var json = JsonProcessor();
json.process();
// JSONファイルを読み取り中
// JSONオブジェクトを解析中
// クラウドストレージに保存しました
}process()メソッドはテンプレートです。操作の順序を defines。サブクラスはreadData()とprocessData()を differently implementし、必要に応じてsaveData()をオーバーライドできます。主な利点は、個々のステップに柔軟性を持たせながら、algorithmの構造をすべての実装で一貫させられることです。
チャレンジ
簡単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パターンによってalgorithmの構造を一貫させながらカスタマイズできる方法を示します。SalesReportを作成し、そのgenerate()メソッドを呼び出します。次に、区切りとして空行を出力します。InventoryReportも作成し、そのgenerate()メソッドを呼び出します。
2つのレポートが同じ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.自分で試してみよう
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まとめ:ジェネリックなストレージ自分で練習してみよう: Dartオンラインコンパイラ