Menu
Coddy logo textTech

デザインパターン入門

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つのデザインパターンのカテゴリについての理解を示す、シンプルなパターン分類器(classifier)を作成しましょう。パターンの名前を受け取り、それがどのカテゴリ(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つのカテゴリについての理解を深めるものです。マルチファイル構造は、実際のプロジェクトで関連するクラスをどのように整理するかを反映しています。

チートシート

デザインパターンは、一般的なソフトウェア設計の問題に対する再利用可能な解決策です。これらは、直接コピーするコードではなく、クラスやオブジェクトを構造化するためのテンプレートとして機能します。

デザインパターンは、主に3つのカテゴリに分類されます:

カテゴリ 目的
生成 (Creational) オブジェクト生成のメカニズム Singleton, Factory, Builder
構造 (Structural) クラスとオブジェクトの構成 Adapter, Decorator, Composite
振る舞い (Behavioral) オブジェクト間の相互作用と責務 Observer, Strategy, Command

デザインパターンの利点:

  • 開発者間での共通語彙を提供します
  • 一般的な問題に対する解決策の再発明を避けることができます
  • コードの柔軟性と保守性を向上させます

C++において、デザインパターンは継承、ポリモーフィズム、抽象クラス、テンプレートなどのOOP(オブジェクト指向プログラミング)機能を活用します。

自分で試してみよう

#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腕試し

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

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