Menu
CoddyTech

デザインパターン入門

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の機能である継承、ポリモーフィズム、抽象クラス、テンプレートを活用します。これからのレッスンでは、いくつかの重要なパターンを実装し、それぞれがどのような場面で適切な手段となるのかを理解します。

challenge icon

チャレンジ

簡単

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を返します。

  • 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;
}
quiz icon腕試し

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

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

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