背景
Decoratorパターンって何?デコレーション?美味しいの?
「オブジェクトに対して新たな責務を動的に付加する。
Decoratorによって、サブクラス化による機能拡張よりも柔軟な代替策が実現できる」
意味がわからないので、考えてみました。
参考文献
参考記事:
あとから記事を見つけて、これ見たほうがわかりやすかった笑
題材
Decoratorパターンの本質としては、以下を解決するものとして記載があります。
- 複数の追加機能が存在している。
- 追加機能群が規則に従っているかどうか判らない。
- クライアントに余計なことを考えさせることなく、追加機能を特定の順序で付加する仕組みが必要。
- どの追加機能を使用しているのかをアプリケーション側に意識させたくない。
このサンプルを考えるときの身近な例としては、HUNTER×HUNTERのクラピカvsウヴォーギンの戦いが浮かびました。
クラピカの念能力として、色々使えるけど、鎖の念能力を使う順番とかは決まってないとして、
それらを簡単に呼び分けられたら良いと考えました。
クラス設計
実装
- 抽象クラス
#pragma once
#include <iostream>
class nennnouryokusha{
public:
virtual void nennnouryoku();
nennnouryokusha(){}
~nennnouryokusha(){}
};
#include <iostream>
#include "nennouryokusha_decorator.h"
/* Concrete */
void nennnouryokusha_decorator::call_nennnouryoku(){
mynennnouryokusha->nennnouryoku();
};
#pragma once
#include <iostream>
#include "nennouryokusha.h"
class nennnouryokusha_decorator : public nennnouryokusha {
private:
nennnouryokusha* mynennnouryokusha;
public:
nennnouryokusha_decorator(nennnouryokusha* _nennnouryokusha) : mynennnouryokusha(_nennnouryokusha){}
void call_nennnouryoku();
~nennnouryokusha_decorator();
};
- 具象クラス
#pragma once
#include <iostream>
#include "nennouryokusha.h"
class kurapika : public nennnouryokusha{
public:
kurapika(){}
~kurapika(){}
};
#include <iostream>
#include "kurapika.h"
/* Concrete */
void nennnouryokusha::nennnouryoku(){
std::cout << "emperor time!!\r\n";
}
#pragma once
#include <iostream>
#include "nennouryokusha_decorator.h"
class chain_jail : public nennnouryokusha_decorator {
public:
chain_jail(nennnouryokusha* _nennnouryokusha) : nennnouryokusha_decorator(_nennnouryokusha){}
void nennnouryoku();
~chain_jail();
};
class judgement_chain : public nennnouryokusha_decorator {
public:
judgement_chain(nennnouryokusha* _nennnouryokusha) : nennnouryokusha_decorator(_nennnouryokusha){}
void nennnouryoku();
~judgement_chain();
};
class steal_chain : public nennnouryokusha_decorator {
public:
steal_chain(nennnouryokusha* _nennnouryokusha) : nennnouryokusha_decorator(_nennnouryokusha){}
void nennnouryoku();
~steal_chain();
};
#include <iostream>
#include "chain.h"
/* Concrete */
void chain_jail::nennnouryoku(){
std::cout << "chain_jail\r\n";
nennnouryokusha_decorator::call_nennnouryoku();
}
void judgement_chain::nennnouryoku(){
std::cout << "judgement_chain\r\n";
nennnouryokusha_decorator::call_nennnouryoku();
}
void steal_chain::nennnouryoku(){
std::cout << "steal_chain\r\n";
nennnouryokusha_decorator::call_nennnouryoku();
}
- メイン
チェーンジェイル、スチールチェーン、ジャッジメントチェーンの順番を入れ替えたkurapika1とkurapika2があります。
#include <iostream>
#include "nennouryokusha.h"
#include "kurapika.h"
#include "chain.h"
int main(){
nennnouryokusha *kurapika1;
nennnouryokusha *kurapika2;
/* スチールチェーン→ジャッジメントチェーン→チェーンジェイル */
kurapika1 = new steal_chain(new judgement_chain(new chain_jail(new kurapika)));
kurapika1->nennnouryoku();
std::cout << "\r\n\r\n---test---\r\n\r\n";
/* チェーンジェイル→スチールチェーン→ジャッジメントチェーン */
kurapika2 = new chain_jail(new steal_chain(new judgement_chain(new kurapika)));
kurapika2->nennnouryoku();
}
実行結果
Decorator % g++ -o test kurapika.cpp main.cpp chain.cpp nennnouryokusha_decorator.cpp
Decorator % ./test
steal_chain
judgement_chain
chain_jail
emperor time!!
---test---
chain_jail
steal_chain
judgement_chain
emperor time!!
Decorator %
結論
Decoratorパターンの使い所である、複数の機能がどういう順番で呼び出されるか判らないケースとして、クラピカの絶対時間(エンペラータイム)を題材にDecoratorパターンを作ってみました。
結果、クラピカを題材にしたのは分かりづらかったかもしれない!と思いました。笑
ぼくの大好きなCoCo壱のカレーのほうがわかりやすかったなと。
トッピングとしてパリパリチキン・チキンカツ・ソーセージ・ほうれん草などがあって、合計いくらになるのか?などでDecoratorパターン適用したほうが題材として適切だったような気がします。
ただ、僕のやりたいことは、よく判らないことを身近なものを題材にサンプルを作成する、
なのでそういう意味では目標達成できました。