Day 27では、デザインパターンのうち「構造型パターン」について学習します。
構造型パターンは、クラスやオブジェクトの構造を改良するためのパターンです。主な構造型パターンには、アダプタ、デコレータ、コンポジット、ブリッジ、ファサードなどがあります。
以下に構造型パターンの主な内容と、例題、演習問題を提示します。
構造型パターンの主な内容:
1. アダプタパターン:
– アダプタパターンは、既存のクラスのインターフェースを別のインターフェースに変換するパターンです。
– 互換性のないクラスを連携させることができます。
2. デコレータパターン:
– デコレータパターンは、オブジェクトに対して動的に機能を追加するパターンです。
– サブクラスを作成することなく、機能を追加できます。
3. コンポジットパターン:
– コンポジットパターンは、オブジェクトの階層構造を木構造で表現するパターンです。
– 個々のオブジェクトと合成オブジェクトを同じように扱えます。
4. ブリッジパターン:
– ブリッジパターンは、抽象と実装を分離してそれぞれ独立に拡張できるパターンです。
– 機能と実装を柔軟に組み合わせることができます。
5. ファサードパターン:
– ファサードパターンは、複雑なサブシステムのインターフェースを単純化するパターンです。
– クライアントが使いやすいインターフェースを提供します。
例題:
デコレータパターンの例として、コーヒーを注文して様々なトッピングを追加するプログラムを考えてみましょう。
#include <iostream> #include <string> // コーヒーの抽象クラス class Coffee { public: virtual std::string getDescription() const = 0; virtual double cost() const = 0; }; // ベースのコーヒー class SimpleCoffee : public Coffee { public: std::string getDescription() const override { return "Simple Coffee"; } double cost() const override { return 100.0; } }; // コーヒーのトッピングを表すデコレータ class CoffeeDecorator : public Coffee { protected: Coffee* coffee; public: CoffeeDecorator(Coffee* coffee) : coffee(coffee) {} std::string getDescription() const override { return coffee->getDescription(); } double cost() const override { return coffee->cost(); } }; // ミルクのトッピング class MilkDecorator : public CoffeeDecorator { public: MilkDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {} std::string getDescription() const override { return coffee->getDescription() + ", Milk"; } double cost() const override { return coffee->cost() + 50.0; } }; // シロップのトッピング class SyrupDecorator : public CoffeeDecorator { public: SyrupDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {} std::string getDescription() const override { return coffee->getDescription() + ", Syrup"; } double cost() const override { return coffee->cost() + 70.0; } }; int main() { Coffee* coffee = new SimpleCoffee(); coffee = new MilkDecorator(coffee); coffee = new SyrupDecorator(coffee); std::cout << "Description: " << coffee->getDescription() << std::endl; std::cout << "Cost: " << coffee->cost() << " yen" << std::endl; delete coffee; return 0; }
演習問題:
1. コンポジットパターンを使って、ファイルシステムの階層構造を表現するプログラムを作成してください。ディレクトリとファイルを同じように扱えるようにしてください。
2. ファサードパターンを使って、オーディオプレーヤーの制御を行うプログラムを作成してください。再生、停止、次の曲へのスキップなどの機能を提供するファサードを作成し、クライアントがシンプルなインターフェースで操作できるようにしてください。
これらの例題と演習問題を解くことで、構造型パターンの理解と実践ができます。問題を解いたら、各パターンが正しく動作しているかどうかを確認してみてください。