デザインパターン入門
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 90/104。
デザインパターンとは、ソフトウェア設計でよく発生する問題に対する、実績のある再利用可能な解決策です。直接コピーして使うコードではなく、特定の課題をエレガントに解決するために、クラスやオブジェクトをどのように構成すればよいかを示すテンプレートや設計図です。
この概念は、1994年に23の基本的なパターンをまとめた書籍を出版した「Gang of Four」(GoF)によって広まりました。これらのパターンは通常、次の3つのカテゴリに分類されます。
| カテゴリ | 目的 | 例 |
|---|---|---|
| Creational | オブジェクトの生成メカニズム | Singleton、Factory、Builder |
| Structural | クラスとオブジェクトの構成 | Adapter、Decorator、Composite |
| Behavioral | オブジェクトの相互作用と責任 | Observer、Strategy、Command |
なぜデザインパターンを学ぶのでしょうか?デザインパターンは開発者同士の共通語彙となり、「ここではFactoryを使おう」と言うだけで、複雑な考えをすぐに伝えられます。また、解決策を一から考え直す手間を省き、コードの柔軟性と保守性を高めるのにも役立ちます。
C++では、デザインパターンは、これまでに学んだOOPの機能である継承、ポリモーフィズム、抽象クラス、テンプレートを活用します。これからのレッスンでは、いくつかの重要なパターンを実装し、それぞれがどのような場面で適切な手段となるのかを理解します。
チャレンジ
簡単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++オンラインコンパイラ