Skip to content

Instantly share code, notes, and snippets.

@meki
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save meki/8426b8643f038340eb25 to your computer and use it in GitHub Desktop.
Save meki/8426b8643f038340eb25 to your computer and use it in GitHub Desktop.
クラスにリスナインターフェースとオブザーバリストメンバ変数を追加するマクロ ref: http://qiita.com/_meki/items/b631e8f51aa8db00ff9e
class Foo extends View.OnClickListener {
class Bar : public Foo::OnDoSomethingListener {
void onDoSomething(const Foo& f)
{
// f が do something したら Bar も何かやる
}
}
/* 何かの処理 */ {
Bar bar1;
Bar bar2;
Foo foo;
// bar1, bar2 を foo のリスナーとして登録
foo.setUpdateListener(bar1);
foo.setUpdateListener(bar2);
foo.doSomething();
// ここで bar1, bar2 の onDoSomethingListener が呼ばれる
}
class Foo {
public:
//! Foo の DoSomething を監視するクラスのインターフェース
class DoSomethingListener {
public:
//! アップデート受信のための関数.
virtual void onDoSomething(const Foo & obj) = 0;
};
// スマートポインタをついでに typedef しておく
typedef std::shared_ptr<DoSomethingListener>
PtrDoSomethingListener;
//! リスナー登録.
void setDoSomethingListener(const PtrDoSomethingListener& p) {
listDoSomethingListener.push_back(p);
}
private:
//! Update を通知.
void notifyDoSomething() {
for(auto p : listDoSomethingListener) {
p->onDoSomething(*this);
}
}
//! 登録されているリスナーのリスト
std::vector<PtrDoSomethingListener> listDoSomethingListener;
}
class Bar : public Foo::OnDoSomethingListener {
public:
void onDoSomething(const Foo& obj) override {}
}
#include <iostream>
#include <string>
#include <memory>
#include <vector>
using namespace std;
class Aniki {
// テンプレ
public:
class YaranaikaListener {
public:
virtual void onYaranaika(const Aniki& obj) = 0;
};
typedef shared_ptr<YaranaikaListener> PtrYaranaikaListener;
void setYaranaikaListener(const PtrYaranaikaListener& p) {
listYaranaikaListener.push_back(p);
}
private:
void notifyYaranaika() {
for(auto p : listYaranaikaListener) {
p->onYaranaika(*this);
}
}
std::vector<PtrYaranaikaListener> listYaranaikaListener;
// Aniki クラス個別の処理
public:
Aniki(const string& name) : m_name(name) {}
void yaranaika() {
cout << m_name << ": やらないか" << endl;
// やらないかをリスナーに通知
notifyYaranaika();
}
const string& getName() const { return m_name; }
private:
string m_name;
};
class Shatei : public Aniki::YaranaikaListener {
public:
Shatei(string name) : m_name(name) {}
void onYaranaika(const Aniki& obj) override
{
cout << m_name << ": " << obj.getName() << "兄貴ィィッ-----!" << endl;
}
private:
string m_name;
};
typedef shared_ptr<Shatei> PtrShatei;
int main() {
// 舎弟を作成
PtrShatei a(new Shatei("アドン"));
PtrShatei s(new Shatei("サムソン"));
PtrShatei u(new Shatei("うみにん"));
// アニキを作成
Aniki aniki("イダテン");
// 舎弟を登録
aniki.setYaranaikaListener(a);
aniki.setYaranaikaListener(s);
aniki.setYaranaikaListener(u);
// やらないか
aniki.yaranaika();
return 0;
}
イダテン: やらないか
アドン: イダテン兄貴ィィッ-----!
サムソン: イダテン兄貴ィィッ-----!
うみにん: イダテン兄貴ィィッ-----!
//! クラスの冒頭に書くとリスナインターフェースとオブザーバリストを追加できるマクロ
//! @param _class クラス名
//! @param _what イベント名, On[_what]Listener というインターフェースが追加される.
#define REGISTER_LISTENER(_class, _what) \
public: \
class _what ## Listener { \
public: \
virtual void on ## _what (const _class & obj) = 0; \
}; \
\
typedef std::shared_ptr< _what ## Listener > Ptr ## _what ## Listener; \
\
void set ## _what ## Listener(const Ptr ## _what ## Listener& p) { \
list ## _what ## Listener.push_back(p); \
} \
\
private: \
void notify ## _what () { \
for(auto p : list ## _what ## Listener) { \
p->on ## _what (*this); \
} \
} \
std::vector<Ptr ## _what ## Listener> list ## _what ## Listener;
class Aniki {
// OnYaranaikaListener を追加
REGISTER_LISTENER(Aniki, Yaranaika)
// OnLoveListener を追加
REGISTER_LISTENER(Aniki, Love)
public:
Aniki(const string& name) : m_name(name) {}
void yaranaika() {
cout << m_name << ": やらないか" << endl;
notifyYaranaika(); // 通知 1
}
void love() {
cout << m_name << ": 愛・・・" << endl;
notifyLove(); // 通知 2
}
const string& getName() const { return m_name; }
private:
string m_name;
};
class Shatei : public Aniki::YaranaikaListener, public Aniki::LoveListener
{
public:
Shatei(const string& name) : m_name(name) {}
// イベント受信 1
void onYaranaika(const Aniki& obj) override {
cout << m_name << ": " << obj.getName() << "兄貴ィィッ-----!" << endl;
}
// イベント受信 2
void onLove(const Aniki& obj) override {
cout << m_name << ": " << "超兄貴!" << endl;
}
private:
string m_name;
};
typedef shared_ptr<Shatei> PtrShatei;
int main() {
Aniki aniki("イダテン");
PtrShatei a(new Shatei("アドン"));
PtrShatei s(new Shatei("サムソン"));
PtrShatei u(new Shatei("うみにん"));
// 舎弟を登録 1
aniki.setYaranaikaListener(a);
aniki.setYaranaikaListener(s);
aniki.setYaranaikaListener(u);
// アニキがアクション 1
aniki.yaranaika();
cout << endl;
// 舎弟を登録 2
aniki.setLoveListener(a);
aniki.setLoveListener(s);
aniki.setLoveListener(u);
// アニキがアクション 2
aniki.love();
return 0;
}
イダテン: やらないか
アドン: イダテン兄貴ィィッ-----!
サムソン: イダテン兄貴ィィッ-----!
うみにん: イダテン兄貴ィィッ-----!
イダテン: 愛・・・
アドン: 超兄貴!
サムソン: 超兄貴!
うみにん: 超兄貴!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment