デザインパターン入門
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 90/104。
Design patternsは、ソフトウェアの設計で生じる一般的な問題に対する、実証済みで再利用可能な解決策です。直接コピーして使うコードではなく、特定の課題を洗練された方法で解決するために、クラスとオブジェクトをどのように構成するかを示すテンプレートや設計図です。
この概念は「Gang of Four」(GoF)が1994年の著書で広めたもので、その中では23の基本的なパターンが体系化されています。これらのパターンは通常、次の3つのカテゴリに分類されます。
| カテゴリ | 目的 | 例 |
|---|---|---|
| Creational | Object の creation メカニズム | Singleton、Factory、Builder |
| Structural | Class と object の composition | Adapter、Decorator、Composite |
| Behavioral | Object の interaction と責任 | Observer、Strategy、Command |
なぜ design patterns を学ぶのでしょうか。design patterns は開発者間で共有される語彙を提供します。「ここでは Factory を使う」と言うだけで、複雑な考えをすぐに伝えられます。また、解決策を一から作り直すことを避け、コードをより柔軟で保守しやすくするのにも役立ちます。
C++では、design patternsはすでに学んだOOPの機能、つまり継承、ポリモーフィズム、抽象クラス、テンプレートを活用します。これからのレッスンでは、いくつかの重要なpatternsを実装し、それぞれがどのような場合に適したツールなのかを理解していきます。
チャレンジ
簡単3つのデザインパターンカテゴリについての理解を示す、シンプルなパターンクラシファイアを構築しましょう。パターン名を受け取り、それが属するカテゴリ(Creational、Structural、または Behavioral)を、そのカテゴリの目的の簡単な説明とともに特定するシステムを作成します。
コードを3つのファイルに分けて整理します。
PatternCategory.h:デザインパターンカテゴリを表す、PatternCategoryという名前の抽象基底クラスを定義します。このクラスには次のものを含めます。- カテゴリ名を文字列として返す純粋仮想メソッド
getName() - このカテゴリに属するパターンが何をするものかの説明を返す純粋仮想メソッド
getPurpose() - 仮想デストラクタ
次に、
PatternCategoryを継承する3つの派生クラスを作成します。CreationalCategory:名前として"Creational"、目的として"Object creation mechanisms"を返しますStructuralCategory:名前として"Structural"、目的として"Class and object composition"を返しますBehavioralCategory:名前として"Behavioral"、目的として"Object interaction and responsibility"を返します
- カテゴリ名を文字列として返す純粋仮想メソッド
PatternClassifier.h:指定されたパターンがどのカテゴリに属するかを特定できるPatternClassifierクラスを作成します。クラシファイアには、パターン名(文字列)を受け取り、適切な
PatternCategoryへのポインタを返すclassifyメソッドを用意します。メモリ管理にはスマートポインタ(std::unique_ptr)を使用してください。クラシファイアは、次のパターンを認識する必要があります。
- Creational:
Singleton、Factory、Builder - Structural:
Adapter、Decorator、Composite - Behavioral:
Observer、Strategy、Command
パターン名が認識されない場合は、
nullptrを返します。- Creational:
main.cpp:1つの入力、つまりデザインパターンの名前を読み取ります。PatternClassifierを作成し、それを使用して入力されたパターンを分類します。パターンが認識された場合は、次を出力します。[PatternName] is a [CategoryName] pattern Purpose: [CategoryPurpose]パターンが認識されない場合は、次を出力します。
Unknown pattern: [PatternName]
たとえば、入力が Singleton の場合:
Singleton is a Creational pattern
Purpose: Object creation mechanisms入力が Observer の場合:
Observer is a Behavioral pattern
Purpose: Object interaction and responsibility入力が Proxy の場合:
Unknown pattern: Proxyこのチャレンジでは、継承、ポリモーフィズム、スマートポインタを実践しながら、デザインパターンの3つのカテゴリについての理解を深めます。これらはすべて、すでに習得した概念です。複数ファイルによる構成は、実際のプロジェクトで関連するクラスを整理する方法を反映しています。
自分で試してみよう
#include <iostream>
#include <string>
#include "PatternClassifier.h"
int main() {
// パターン名を読み取る
std::string patternName;
std::cin >> patternName;
// TODO: PatternClassifier のインスタンスを作成する
// TODO: 分類器を使用して入力パターンを分類する
// TODO: パターンが認識された場合、以下を出力する:
// "[PatternName] is a [CategoryName] pattern"
// "Purpose: [CategoryPurpose]"
// TODO: パターンが認識されない場合 (nullptr)、以下を出力する:
// "Unknown pattern: [PatternName]"
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ