Last active
July 3, 2018 14:46
-
-
Save mortennobel/6327279 to your computer and use it in GitHub Desktop.
C++11 Observer Version 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Event.h | |
// | |
// Created by Morten Nobel-Jørgensen on 8/18/13. | |
// Copyright (c) 2013 morten. All rights reserved. | |
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause) | |
#pragma once | |
#include <iostream> | |
#include <functional> | |
#include "EventListener.h" | |
#include <vector> | |
#include <utility> | |
class AbstractEvent{ | |
public: | |
virtual bool removeListener(int id) = 0; | |
}; | |
template <typename E> | |
class Event : public AbstractEvent{ | |
public: | |
EventListener<E> createListener(std::function<void (E)> listener){ | |
listeners.emplace_back(listener, eventListenerId); | |
eventListenerId++; | |
return EventListener<E>(this, eventListenerId-1); | |
} | |
void registerSyncValue(SyncValue<E>& syncValue){ | |
if (syncValue.listenerId > -1){ | |
removeListener(syncValue.listenerId); | |
} | |
std::function<void (E)> updateFunction = [&](E e){ | |
syncValue.value = e; | |
}; | |
listeners.emplace_back(updateFunction, eventListenerId, 0); | |
syncValue.listenerId = eventListenerId; | |
syncValue.ae = this; | |
eventListenerId++; | |
} | |
void notifyListeners(E e){ | |
for (auto & l : listeners){ | |
l.first(e); | |
} | |
} | |
bool removeListener(int id){ | |
auto iter = listeners.begin(); | |
while (iter != listeners.end()){ | |
if (iter->second == id){ | |
listeners.erase(iter); | |
return true; | |
} | |
iter++; | |
} | |
return false; | |
} | |
protected: | |
std::vector<std::pair<std::function<void (E)>, int>> listeners; | |
friend class EventListener<E>; | |
int eventListenerId = 0; | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventListener.cpp | |
// | |
// Created by Morten Nobel-Jørgensen on 8/18/13. | |
// Copyright (c) 2013 morten. All rights reserved. | |
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause) | |
#include "EventListener.h" | |
#include "Event.h" | |
AbstractEventListener::AbstractEventListener(AbstractEvent *ae, int listenerId) | |
:ae(ae), listenerId(listenerId){ | |
} | |
AbstractEventListener::~AbstractEventListener(){ | |
destroyListener(); | |
} | |
void AbstractEventListener::destroyListener(){ | |
if (ae){ | |
ae->removeListener(listenerId); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// EventListener.h | |
// | |
// Created by Morten Nobel-Jørgensen on 8/18/13. | |
// Copyright (c) 2013 morten. All rights reserved. | |
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause) | |
#pragma once | |
#include <iostream> | |
class AbstractEvent; | |
class AbstractEventListener{ | |
public: | |
AbstractEventListener(){}; | |
AbstractEventListener(AbstractEvent *ae, int listenerId); | |
AbstractEventListener(const AbstractEventListener&) = delete; | |
AbstractEventListener& operator=( const AbstractEventListener& rhs ) = delete; | |
virtual ~AbstractEventListener(); | |
friend class AbstractEvent; | |
protected: | |
void destroyListener(); | |
int listenerId = -1; | |
AbstractEvent *ae = nullptr; | |
}; | |
template <typename E> | |
class Event; | |
template <typename E> | |
class EventListener : public AbstractEventListener { | |
public: | |
EventListener(){ | |
} | |
EventListener(Event<E> *e, int listenerId) | |
:AbstractEventListener(e, listenerId) | |
{ | |
} | |
EventListener(const EventListener&) = delete; | |
EventListener& operator=( const EventListener& rhs ) = delete; | |
EventListener(EventListener&& other){ | |
listenerId = other.listenerId; | |
ae = other.ae; | |
other.ae = nullptr; | |
} | |
EventListener& operator=( EventListener&& rhs ) { | |
if (this != &rhs){ | |
destroyListener(); | |
listenerId = rhs.listenerId; | |
ae = rhs.ae; | |
rhs.ae = nullptr; | |
} | |
return *this; | |
}; | |
friend class Event<E>; | |
}; | |
template <typename E> | |
class SyncValue : public AbstractEventListener { | |
public: | |
SyncValue(){ | |
} | |
E& getValue(){ | |
return value; | |
} | |
SyncValue(const SyncValue&) = delete; | |
SyncValue& operator=( const SyncValue& rhs ) = delete; | |
SyncValue(SyncValue&& other){ | |
listenerId = other.listenerId; | |
ae = other.ae; | |
value = std::move(other.value); | |
other.ae = nullptr; | |
} | |
SyncValue& operator=( SyncValue&& rhs ) { | |
if (this != &rhs){ | |
destroyListener(); | |
listenerId = rhs.listenerId; | |
ae = rhs.ae; | |
value = std::move(rhs.value); | |
rhs.ae = nullptr; | |
} | |
return *this; | |
}; | |
friend class Event<E>; | |
private: | |
E value; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.cpp | |
// Observer pattern in C++11 | |
// | |
// Created by Morten Nobel-Jørgensen on 8/18/13. | |
// Copyright (c) 2012 Morten Nobel-Joergensen. All rights reserved. | |
// Open Source under New BSD License (http://opensource.org/licenses/BSD-3-Clause) | |
#include <iostream> | |
#include <iostream> | |
#include <functional> | |
#include <vector> | |
#include <map> | |
#include <string> | |
#include <utility> | |
#include "Event.h" | |
#include "EventListener.h" | |
using namespace std; | |
class Foo { | |
public: | |
Foo(){ | |
} | |
Event<int> event; | |
void setValue(int i){ | |
value = i; | |
event.notifyListeners(i); | |
} | |
private: | |
int value; | |
}; | |
class Moo { | |
public: | |
Moo(Foo *f) { | |
f->event.registerSyncValue(syncVal); | |
eventListener = f->event.createListener([](int v){ | |
cout<<"Value is "<<v<<endl; | |
}); | |
} | |
SyncValue<int> syncVal; | |
private: | |
EventListener<int> eventListener; | |
}; | |
int main(int argc, const char * argv[]) | |
{ | |
Foo f; | |
{ | |
Moo m(&f); | |
f.setValue(123); | |
cout << "synched value " << m.syncVal.getValue()<<endl;; | |
f.setValue(12); | |
cout << "synched value " << m.syncVal.getValue()<<endl;; | |
} | |
f.setValue(1234); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment