Knowing that this might be an inappropriate question (since the reply can be (will be) based only on personal, subjective opinions) I still risk asking it:
We wrote some code and came up with the following construct
#include <iostream>
#include <string>
class Generic
{
public: virtual void do_work() = 0;
};
class SomeAppDescriptor : public Generic
{
public: static std::string name() { return "SomeAppDescriptor"; }
};
template <class TGenericApp>
class CommonFunctionalities : public TGenericApp
{
public: void do_common_work() {
std::cout << "do_common_work for " << TGenericApp::name();
}
};
class RealClass : public CommonFunctionalities<SomeAppDescriptor>
{
public: virtual void do_work() {
do_common_work();
std::cout << "and doing the work" << std::endl;
}
};
int main(int argc, char const *argv[])
{
RealClass a;
a.do_work();
return 0;
}
And now we are in the documentation phase ... We need to come up with a name for the construct where CommonFunctionalities inherits from the template member ... and is using the properties of the SomeAppDescriptor which is actually the template member... If you are to name this construct, what would be an appropriate name for it?
Edit
The main idea is that there are a lot of AppDescriptor classes which read some data from configuration files (name, ip, database, etc ...), and there is a middle layer (here it is represented by CommonFunctionalities which does the work (but also at some obscure point the CommonFunctionalities objects are mapped to name() (map of string and Generic) in order to get the functionality of the do_work()), and at the end someone from somewhere is calling the do_work of a Generic which is implemented in a set of "upper" layer classes (RealClass)
This looks, to me, like a botched attempt at a Decorator.
SomeAppDescriptor and CommonFunctionalities do not override do_work, so they need not inherit from Generic; however the use of do_common_work suggests that might have been useful.
if RealClass inherits from Generic directly, then it can take CommonFunctionalities by composition.
Using the Decorator pattern, I would end up with:
class Generic { public: virtual void do_work() = 0; };
template <typename App>
class CommonFunctionalities: public Generic {
public:
virtual void do_work() override {
std::cout << "CommonFunctionalities - " << App::name() << "\n";
}
};
class RealClass: public Generic {
public:
RealClass(std::unique_ptr<Generic> p): previous(std::move(p)) {}
virtual void do_work() override {
if (previous) { previous->do_work(); }
std::cout << "RealClass\n";
}
private:
std::unique_ptr<Generic> previous;
};
int main() {
RealClass rc{std::make_unique< CommonFunctionalities<SomeAppDescriptor> >()};
Generic& g = rc;
g.do_work();
return 0;
}
The Decorator was specifically created to layer the work, without any class knowing more than the interface class so that you can at runtime choose which layers to use. Even if the runtime flexibility is not necessary, it can still be advantageous to use this approach because it reduces the dependencies: RealClass knows not of CommonFunctionalities.
Note: in C++, you can also use the Decorator approach without interfaces thanks to templates.
It's the Curiously Recurring Template Pattern.
I think it's somewhat of an upgrade to the Curiously Recurring Template Pattern.
looks nice. :)
Related
I want to implement a class hierarchy for object dispatching. Different classes dispatch different elements, and each class can dispatch its element represented as different data types.
It is better understood through a (faulty) example. This is what I would like to have if virtual function templating was allowed:
class Dispatcher {
template <class ReturnType>
virtual ReturnType getStuffAs();
};
So that I can implement subclasses as:
class CakeDispatcher : public Dispatcher {
template <>
virtual Recipe getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
};
class DonutDispatcher : public Dispatcher {
template <>
virtual Frozen getStuffAs(){ ... }
template <>
virtual Baked getStuffAs(){ ... }
}
So that I can do the following later on:
void function( Dispatcher * disp ) {
// Works for Donut and Cake, but result will be a different Baked object
Baked b = disp->getStuffAs<Baked>();
// works if disp points to a DonutDispatcher
// fails if it is a CakeDispatcher
// can be compiling/linking time error or runtime error. I don't care
Frozen f = disp->getStuffAs<Frozen>();
}
Requirements/constraints:
All possible return types are not known beforehand. That's why I "need" templates.
Each class can provide just some return types.
Classes must have a common ancestor, so that I can store objects through a pointer to parent class and invoke functions through this pointer.
EDIT: I CAN'T use C++11 features, but I CAN use boost library.
Things I've thought about, but are not a solution:
Obviously, virtual template functions
Curiously Recurring Template Pattern: breaks the condition of common ancestor
Using some kind of traits class containing the functionality of children classes, but it does not work because a non-virtual implementation in the parent class does not have access to this information
I could maybe store some typeid info in the parent class, passed by children on construction. This makes possible for the non-virtual parent dispatching method to dynamic-cast itself to the children type... but it appears to be ugly as hell, and I don't know if this can cause some kind cycle-referencing problem.
class Dispatcher {
private:
typeid(?) childType;
public:
Dispatcher(typeid childT) : childType(childT) {}
// NOT VIRTUAL
template <class ReturnType>
ReturnType getStuffAs()
{
// or something equivalent to this cast, which I doubt is a correct expression
return dynamic_cast<childType *>(this)->childGetStuffAs<ReturnType>();
}
};
Then child classes would implement childGetStuffAs functions, which are not virtual too.
I've read like 5-10 related questions, but none of the provided solutions seems to fit this problem.
Can any of you come up with a better solution?
Is there a standard pattern/technique for solving this problem?
EDIT: The real problem
In the real problem, I have physical models with properties that can be represented in multiple ways: functions, matrices, probability distributions, polynomials, and some others (for example, a non-linear system can be represented as a function but not as a a matrix, while a linear system can be transformed to both).
There are also algorithms which can use those models indistinctly, but they could require specific representations for some model features. That's the reason for the "getStuffAs" function. The whole think is a bit complicated --too much to explain it here properly--, but I can guarantee that in this context the interface is well defined: input, computation and output.
My intention was to make this possible assuming that the number of possible representations is fully defined beforehand, and making it possible to transform the products to already existing types/classes that cannot be modified.
However, i'm starting to realize that this is, indeed, not possible in a simple way --I don't want to write a library just for this problem.
#include <cstdio>
// as a type identifier
struct stuff {
virtual void foo() {}
};
template <typename T>
struct stuff_inh : stuff {
};
struct Dispatcher {
template <typename T>
T* getStuffAs() {
return (T*)((getStuffAsImpl( new stuff_inh<T>() )));
}
virtual void* getStuffAsImpl(void*) = 0;
virtual void type() {printf("type::dispatcher\n");}
};
struct Cake : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("cake impl\n");
if (dynamic_cast<stuff_inh<Cake>*>(s) == NULL) {
throw "bad cast";
}
return (void*)(new Cake());
}
virtual void type() {printf("type::Cake\n");}
};
struct Rabbit : public Dispatcher {
void* getStuffAsImpl(void* p) {
stuff* s = static_cast<stuff*>(p);
printf("rabbit impl\n");
if (dynamic_cast<stuff_inh<Rabbit>*>(s) != NULL) {
return (void*)(new Rabbit());
}
else if (dynamic_cast<stuff_inh<Cake>*>(s) != NULL) {
return (void*)(new Cake());
}
else {
throw "bad cast";
}
}
virtual void type() {printf("type::Rabbit\n");}
};
void foo(Dispatcher* d) {
d->getStuffAs<Cake>()->type();
d->getStuffAs<Rabbit>()->type();
}
int main() {
Rabbit* r = new Rabbit;
foo(r);
Cake* c = new Cake;
foo(c);
}
I an not sure about the correctness of this ugly solution, may it be helpful for you. >_<
deletion of resource is not coded for a clearer look.
My solution is a combination of recurring template and diamond inheritance.
At least it's working. :)
#include <iostream>
class Dispatcher
{
public:
template<class T>
T getStuff()
{
return T();
}
};
template<class T>
class Stuffer : public Dispatcher
{
public:
template<class TT=T>
TT getStuff(){
return reinterpret_cast<TT>(this);
}
};
class Cake{
public:
Cake(){}
void print()
{
std::cout << "Cake" << std::endl;
}
};
class Recipe
{
public:
Recipe(){}
void print()
{
std::cout << "Recipe" << std::endl;
}
};
class CakeRecipe : public Stuffer<Cake>, public Stuffer< Recipe >
{
public:
};
int main()
{
Dispatcher* cr = reinterpret_cast<Dispatcher*>(new CakeRecipe());
cr->getStuff<Cake>().print();
cr->getStuff<Recipe>().print();
getchar();
return 1;
}
In the product I am working, one of very basic scenario is serialization of classes. Typically a class to be serialized calls serialization on its sub-component
e.g. if there is a class s.t. class
A{B;C;D;} then A.Pack will call pack
function on B,C,D.
Since there are many such classes, same pattern of code has to be duplicated over and over again.
Is it possible to encapsulate this behavior in a pattern (possibly using templates and inheritance)
The usual way of making a template do this is to use a type list:
#include <iostream>
// typelist definition
struct Empty {};
template < typename H, typename T = Empty >
struct Cons {
typedef H head;
typedef T tail;
};
// interfaces all items support
class IPack
{
public:
virtual void Pack() = 0;
};
// some packable items
class Fee : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fee\n";
}
};
class Fi : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fi\n";
}
};
class Fo : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fo\n";
}
};
class Fum : public IPack
{
public:
virtual void Pack() {
std::cout << "Packed Fum\n";
}
};
// these two templates create a composite IPack from a list
// of the types of its parts
template <typename Types>
class PackList : public PackList<typename Types::tail>
{
protected:
typedef typename Types::head Item;
Item item;
public:
virtual void Pack() {
item.Pack();
PackList<typename Types::tail>::Pack();
}
};
template <>
class PackList<Empty> : public IPack
{
public:
virtual void Pack() {}
};
// FeeFiFoFum is a composite of four items
class FeeFiFoFum : public PackList<Cons<Fee,Cons<Fi,Cons<Fo,Cons<Fum> > > > >
{
};
// create a FeeFiFoFum and call pack on it, which calls pack on its parts
int main ()
{
FeeFiFoFum giant;
giant.Pack();
}
Proper implementations of composites created from type lists give you accessors for the members and so on, but this is enough to show how they works, and prints out that it packed Fee, Fi, Fo and Fum without specifying any behaviour.
One possible design that would help accomplish this is to use the Composite pattern. Your Component (to borrow from the Wikipedia drawing) is Packable, which would implement a Template Method Pack() that can do something like so:
GetChildren();
for each child:
child.Pack()
PackImpl();
PackImpl() is a pure virtual method in Packable, and all classes that inherit implement it appropriately. GetChildren() would return an STL container (possibly empty), for iteration. It can be implemented in Packable, along with a private member collection to store the child objects. Basically, you then inherit all the classes from Packable, implement PackImpl(), and you're done.
Note that this will cause issues if your inheritance hierarchy depends on the child pieces being members directly. If you've approached the problem in terms of aggregation, this should work well.
It's possible that the Visitor pattern may help.
http://en.wikipedia.org/wiki/Visitor_pattern
The idea of this is to separate the traversal logic (stepping through your objects) from the handling of each object. In this case, the per-object logic is serializing (encoding) a single object (or deserializing, of course). This should be fairly simple and minimally repetitive using normal OOP techniques.
Implementing the traversal and the Visitor-pattern specific code is annoying, but it's mostly boilerplate and should be a one-off thing.
One commenter wrote:
If you mean "is there a way I can write a template to automatically call a method on each of my member variables?", then the answer is no...
My (slightly evil) counter to that is yes, if the method is the destructor...
#include <iostream>
using namespace std;
bool Enable = false;
template <typename T>
class DS : public T {
public:
~DS() {
if (Enable) T::Serialize();
}
};
class A {
protected:
void Serialize() { cout << "A" << endl; }
};
class B {
protected:
void Serialize() { cout << "B" << endl; }
};
typedef DS<A> DSA;
typedef DS<B> DSB;
class C {
protected:
void Serialize() { cout << "C" << endl; }
private:
DSA a;
DSB b;
};
typedef DS<C> DSC;
int
main()
{
DSC c;
{
DSC c_copy = c;
Enable = true;
}
Enable = false;
}
The output is in reverse order, so to reconstruct objects you'd have to parse the serialized data and push each completed object on a stack. Composite objects would then know how many children to pop off of the stack. Or, of course, the serialization could go to an intermediate structure.
Another intriguing idea would be to use this hack once at startup (create and destroy only one special object) where the callbacks from the destructors would create a data structure that described the original object.
I also note that implicit copy constructors have potential for similar abuse, and possible in forward order...
I need several C++ classes to have a static method "register", however the implementation of register varies between those classes.
It should be static because my idea is to "register" all those classes with Lua (only once of course).
Obviously I can't declare an interface with a static pure virtual function. What do you guys suggest me to do ? Simplicity is welcome, but I think some kind of template could work.
Example of what I would like to achieve
class registerInterface
{
public:
static virtual void register() = 0; //obviously illegal
};
class someClass: public registerInterface
{
static virtual void register()
{
//I register myself with Lua
}
}
class someOtherClass: public registerInterface
{
static virtual void register()
{
//I register myself with Lua in a different way
}
}
int main()
{
someClass::register();
someOtherClass::register();
return 0;
}
Based on how you've described the problem, it's unclear to me why you even need the 'virtual static method' on the classes. This should be perfectly legal.
class SomeClass {
static void register(void) {
...
}
}
class SomeOtherClass {
static void register(void) {
...
}
}
int main(int argc, char* argv[]) {
SomeClass::register();
SomeOtherClass::register();
return 0;
}
Drop the RegisterInterface, I don't think you need it.
If it helps, you could take Hitesh's answer, and add:
struct luaRegisterManager {
template <typename T>
void registrate() {
T::registrate();
// do something else to record the fact that we've registered -
// perhaps "registrate" should be returning some object to help with that
}
};
Then:
int main() {
luaRegisterManager lrm;
lrm.registrate<someClass>();
lrm.registrate<someOtherClass>();
}
More generally, if you want to introduce any dynamic polymorphism in C++, then you need an object, not just a class. So again, perhaps the various register functions should be returning objects, with some common interface base class registeredClass, or classRegistrationInfo, or something along those lines.
Could provide an example of what you feel it is that you need dynamic polymorphism for? Hitesh's code precisely matches your one example, as far as I can see, so that example must not cover all of your anticipated use cases. If you write the code that would be using it, perhaps it will become clear to you how to implement it, or perhaps someone can advise.
Something else that might help:
#include <iostream>
#include <string>
#include <vector>
struct Registered {
virtual std::string name() = 0;
virtual ~Registered() {}
Registered() {
all.push_back(this);
}
static std::vector<Registered*> all;
};
std::vector<Registered*> Registered::all;
typedef std::vector<Registered*>::iterator Iter;
template <typename T>
struct RegisteredT : Registered {
std::string n;
RegisteredT(const std::string &name) : n(name) { T::registrate(); }
std::string name() { return n; }
// other functions here could be implemented in terms of calls to static
// functions of T.
};
struct someClass {
static Registered *r;
static void registrate() { std::cout << "registering someClass\n"; }
};
Registered *someClass::r = new RegisteredT<someClass>("someClass");
struct someOtherClass {
static Registered *r;
static void registrate() { std::cout << "registering someOtherClass\n"; }
};
Registered *someOtherClass::r = new RegisteredT<someOtherClass>("someOtherClass");
int main() {
for (Iter it = Registered::all.begin(); it < Registered::all.end(); ++it) {
std::cout << (*it)->name() << "\n";
}
}
There are all sorts of problems with this code if you try to split it across multiple compilation units. Furthermore, this kind of thing leads to spurious reports from memory leak detectors unless you also write some code to tear everything down at the end, or use a vector of shared_ptr, Boost pointer vector, etc. But you see the general idea that a class can "register itself", and that you need an object to make virtual calls.
In C++ you usually try to avoid static initialisation, though, in favour of some sort of setup / dependency injection at the start of your program. So normally you would just list all the classes you care about (calling a function on each one) rather than try to do this automatically.
Your intentions are noble, but your solution is inkling towards "overengineering" (unless I am missing an obvious solution).
Here is one possibility: You can use the Virtual Friend function idiom For example,
class RegisterInterface{
friend void register(RegisterInterface* x){x->do_real_register();}
protected:
virtual void do_real_register();
}
class Foo : public RegisterInterface{
protected:
virtual void do_real_register(){}
};
class Bar : public RegisterInterface{
protected:
virtual void do_real_register(){}
};
int main(int argc, char* argv[]) {
BOOST_FOREACH(RegisterInterface* ri, registered_interfaces)
{
register(ri);
}
return 0;
}
I know you've already accepted an answer, but I figured I would write this up anyway. You can have self-registering classes if you use some static initialization and the CRTP:
#include <vector>
#include <iostream>
using namespace std;
class RegisterableRoot // Holds the list of functions to call, doesn't actually need
// need to be a class, could just be a collection of globals
{
public:
typedef void (*registration_func)();
protected:
static std::vector<registration_func> s_registery;
public:
static void do_registration()
{
for(int i = 0; i < s_registery.size(); ++i)
s_registery[i]();
}
static bool add_func(registration_func func) // returns something so we can use it in
// in an initializer
{
s_registery.push_back(func);
return true;
}
};
template<typename RegisterableType> // Doesn't really need to inherit from
class Registerable : public RegisterableRoot // RegisterableRoot
{
protected:
static const bool s_effect;
};
class A : public Registerable<A> // Honestly, neither does A need to inherit from
// Registerable<T>
{
public:
static void Register()
{
cout << "A" << endl;
}
};
class B : public Registerable<B>
{
public:
static void Register()
{
cout << "B" << endl;
}
};
int main()
{
RegisterableRoot::do_registration();
return 0;
}
std::vector<RegisterableRoot::registration_func> RegisterableRoot::s_registery;
template <typename RegisterableType> // This is the "cute" part, we initialize the
// static s_effect so we build the list "magically"
const bool Registerable<RegisterableType>::s_effect = add_func(&RegisterableType::Register);
template class Registerable<A>; // Explicitly instantiate the template
// causes the equivalent of
// s_registery.push_back(&A::Register) to
// be executed
template class Registerable<B>;
This outputs
A
B
although I wouldn't rely on this order if I were you. Note that the template class Registerable<X> need not be in the same translation unit as the call to do_registration, you can put it with the rest of your definition of Foo. If you inherit from Registerable<> and you don't write a static void Register() function for your class you'll get a (admittedly probably cryptic) compiler error much like you might expect if there really was such a thing as "static virtuals". The "magic" merely adds the class specific function to the list to be called, this avoids several of the pitfalls of doing the actual registration in a static initializer. You still have to call do_registration for anything to happen.
How about this way? Define an interface class:
// IFoobar.h
class IFoobar{
public:
virtual void Register(void) = 0;
}
Then define the class that handles the register..
// RegisterFoobar.h
class RegisterFoobar{
public:
// Constructors etc...
IFoobar* fooBar;
static void RegisterFoobar(IFoobar& fubar){
foobar = &fubar;
}
private:
void Raise(void){ foobar->Register(); }
}
Now, then define another class like this
// MyFuBar.h
class MyFuBar : IFoobar{
public:
// Constructors etc...
void Register(void);
private:
RegisterFoobar* _regFoobar;
}
Call the code like this:
//MyFuBar.cpp
MyFuBar::MyFuBar(){
_regFoobar = new Foobar();
_regFoobar->RegisterFoobar(this);
}
void MyFuBar::Register(void){
// Raised here...
}
Maybe I have misunderstood your requirements...
A while back I learned about the Curiously Recurring Template Pattern (http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern), and it reminded me of a technique I had used to implement an event queue cache.
The basic idea is that we take advantage of a Base class pointer to store a container of homogeneous pointer types. However because the Derived class is a template class, which stores an item of type T, what we are really storing is a list of heterogeneous types.
I was curious if anyone has seen this technique, which is perhaps interesting, and if so if anyone has named it? Anyone care to critique it? Is there a better way to achieve my end here?
Thanks.
#include <iostream>
#include <algorithm>
#include <functional>
#include <list>
#include <string>
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual void operator()() = 0;
};
template<typename C, typename T>
class Derived : public Base
{
public:
Derived(C* c, T item) : consumer_(c), item_(item) {}
virtual void operator()()
{
consumer_->consume(item_);
}
C* consumer_;
T item_;
};
class Consumer
{
bool postpone_;
std::list<Base*> cache_;
public:
Consumer() : postpone_(true)
{
}
void pause()
{
postpone_ = true;
}
void resume()
{
postpone_ = false;
const std::list<Base*>::iterator end = cache_.end();
for ( std::list<Base*>::iterator iter = cache_.begin();
iter != end;
++iter )
{
Base* bPtr = *iter;
bPtr->operator()();
delete bPtr;
}
cache_.clear();
}
void consume(int i)
{
if ( postpone_ )
{
std::cerr << "Postpone int.\n";
cache_.push_back(new Derived<Consumer, int>(this, i));
}
else
{
std::cerr << "Got int.\n";
}
}
void consume(double d)
{
if ( postpone_ )
{
std::cerr << "Postpone double.\n";
cache_.push_back(new Derived<Consumer, double>(this, d));
}
else
{
std::cerr << "Got double.\n";
}
}
void consume(char c)
{
if ( postpone_ )
{
std::cerr << "Postpone char.\n";
cache_.push_back(new Derived<Consumer, char>(this, c));
}
else
{
std::cerr << "Got char.\n";
}
}
};
static Consumer consumer;
void destroy(Base* object)
{
delete object;
}
int main()
{
// Consumer is registered with something that sends events out to lots
// of different consumer types (think observer pattern). Also in the non-toy
// version consumer isn't being passed PODs, but various Event types.
consumer.consume(0);
consumer.consume(0.1f);
consumer.consume('x');
consumer.resume();
}
The output is:
Postpone int.
Postpone double.
Postpone char.
Got int.
Got double.
Got char.
What you are using is plain polymorphism, as Stephen points out in his comment. While you store different objects internally in the container, you are limited to using the interface defined in Base. That is, of course, unless you intend to add type checking and downcasts to actually retrieve the values. There is just a limited amount of things that you can do with unrelated objects.
Depending on what you are actually wanting to achieve you might consider using other solutions like boost::any/boost::variant if what you want is to actually store unrelated types (in the few cases where this makes sense --cells in a spreadsheet, for example).
anyone has named it?
I think it is an adapter pattern implemented without using inheritance from T.
Anyone care to critique it?
YOu could have used short template function instead of this class. Or you could use template function that returns template class. Template function can automatically guess required types - sou you could omit <> and do less typing.
Nice.
You're utilizing compiler's power to generate templated series of derived classes and it's actually cool that you can mix plain derived classes
(written by yourself) with template-specialized derived classes and with compiler-generated ones
(built as result of template instantiation).
class Base { ... };
template <typename Y> class Derived1 : public Base { ... };
template <specialization>
class Derived1 : public Base { ... };
class Derived2 : public Base { ... };
This could be useful, but it doesn't somehow extend the polymorphism term, because you're still limited to the Base class interface.
Also, you could write a plain factory which would have some templated method for generating subclasses and use it to avoid writing new Derived1<std::string>..., but write something like
std::string a;
Base* base = Factory.Create(a)
I am busy adding a generic observer mechanism to a legacy C++ application (using Visual Studio 2010, but not using .Net, so .Net delegates are out of the question).
In the design I want to separate the application-specific part as much as possible from the generic observer mechanism.
The most logical way of implementing observers seems this way:
class IDoThisObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
For every type of observer (IDoThisObserver, IDoThatObserver, ...) the arguments of the methods (handleDoThis, handleDoThat) are different.
What remains in a generic way of storing the observers, like this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (T &t) {m_observers.push_back(&t);}
private:
std::list<T*> m_observers;
};
Calling an observer can't be generalized since the arguments are different for every observer type.
An alternative way would be to 'pack' all arguments into one argument, like this:
struct DoThisInfo
{
DoThisInfo (int arg1, int arg2) : m_arg1(arg1), m_arg2(arg2) {}
int m_arg1;
int m_arg2;
};
And then define a more generic observer, like this:
template<typename T>
class IObserver
{
public:
void notify(const T &t) = 0;
};
And a collection of these observers would then become this:
template<typename T>
class ObserverContainer
{
public:
void addObserver (IObserver<T> &obs) {m_observers.push_back(&obs);}
private:
std::list<IObserver<T>*> m_observers;
};
Now, much more logic can be centrally added to this ObserverContainer, including calling all observers. The 'initiator' of the call only needs to create and fill in the notification structure.
Classes that want to inherit from multiple kinds of observers, need to do it like this:
class MyObserver : public IObserver<NotifyThis>, public IObserver<NotifyThat>
{
...
};
Which of these approaches (observers with multiple explicit arguments or with one struct argument) seems the best? Are there any advantages or disadvantages to either of these approaches?
EDIT: I looked a bit further to alternative approaches, and the Slot/Signal approach seems another good candidate. Are there any important disadvantages in Slot/Signal that I should know of?
Why not just do:
class IObserver {
// whatever is in common
};
class IDoThisObserver : public IObserver
{
public:
void handlDoThis(int arg1, int arg2) = 0;
};
class IDoThatObserver : public IObserver
{
public:
void handlDoThat(double arg1) = 0;
};
?
Then you have:
class ObserverContainer
{
public:
void addObserver (IObserver* t) {m_observers.push_back(t);}
private:
std::list<IObserver*> m_observers;
};
The design with the struct argument is definitely better as it allows for generic code to be written in the ObserverContainer. It's generally a good design practice to replace longish argument lists with objects that encapsulate the arguments and this is a good example of the payoff. By creating a more general abstraction for your notify method (with the struct you're defining notify as a method that takes a chunk of "data" whereas with the arg list you're defining a method that takes two numbers) you allow yourself to write generic code that uses the method and doesn't have to concern itself with the exact composition of the passed in chunk of data.
Have you looked into Boost.Signals? Better than to reimplement the wheel.
As for Parameters: Calling an observer/slot should conceptionally be the same as if you would call an ordinary function. Most SignalSlots-Implementations allow multiple Parameters, so use it. And please use different signals for different observer types, then there is no need to pass around data in Variants.
Two Disadvantages of the Observer-Pattern/SignalSlots i have seen:
1) Program flow is difficult or even impossible to understand by looking only at the source.
2) Heavily dynamic programs with lots of Observers/SignalSlots may encounter a "delete this"
Everything aside, i like Observers/SignalSlots more than subclassing and thus high coupling.
I don't think either of your approaches would fit your requirement as is. However a little modification using a DataCarrier containing the dataset passed across all the observers wherein each observer would know what to read would do the trick. The sample code below might clear it (note i have not compiled)
enum Type {
NOTIFY_THIS,
NOTIFY_THAT
};
struct Data {
virtual Type getType() = 0;
};
struct NotifyThisData: public Data {
NotifyThisData(int _a, int _b):a(_a), b(_b) { }
int a,b;
Type getType() { return NOTIFY_THIS; }
};
struct NotifyThatData: public Data {
NotifyThatData(std::string _str):str(_str) { }
std::string str;
Type getType() { return NOTIFY_THAT; }
};
struct DataCarrier {
std::vector<Data*> m_TypeData;
};
class IObserver {
public:
virtual void handle(DataCarrier& data) = 0;
};
class NotifyThis: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(), NOTIFY_THIS);
if (iter == data.m_TypeData.end())
return;
NotifyThisData* d = dynamic_cast<NotifyThisData*>(*iter);
std::cout << "NotifyThis a: " << d->a << " b: " << d->b << "\n";
}
};
class NotifyThat: public virtual IObserver {
public:
virtual void handle(DataCarrier& data) {
vector<Data*>::iterator iter = find_if(data.m_TypeData.begin(), data.m_TypeData.end(), bind2nd(functor(),NOTIFY_THAT);
if (iter == data.m_TypeData.end())
return;
NotifyThatData* d = dynamic_cast<NotifyThatData*>(*iter);
std::cout << "NotifyThat str: " << d->str << "\n";
}
};
class ObserverContainer
{
public:
void addObserver (IObserver* obs) {m_observers.push_back(obs);}
void notify(DataCarrier& d) {
for (unsigned i=0; i < m_observers.size(); ++i) {
m_observers[i]->handle(d);
}
}
private:
std::vector<IObserver*> m_observers;
};
class MyObserver: public NotifyThis, public NotifyThat {
public:
virtual void handle(DataCarrier& data) { std::cout << "In MyObserver Handle data\n"; }
};
int main() {
ObserverContainer container;
container.addObserver(new NotifyThis());
container.addObserver(new NotifyThat());
container.addObserver(new MyObserver());
DataCarrier d;
d.m_TypeData.push_back(new NotifyThisData(10, 20));
d.m_TypeData.push_back(new NotifyThatData("test"));
container.notify(d);
return 0;
}
This way u need to modify only the enum if u add a new structure.
Also u can use boost::shared_ptr to handle the mess of pointers.
I wouldn't get the syntax right so I'm just going to list the declarations to illustrate the structures. A generic Observer could be made to expect a parameter that is either subclassed to specific forms of your required parameters or is struct including a horizontal mapping of all primitive parameters that will be required by your Observers. Then the ObserverContainer could function as an AbstractFactory and each subclass of the ObserverContainer could be DoThatObserverFactory and DoThisObserverFactory. The factory would build an observer and assign a configuration to the observer to tell it which parameter to expect.
class AbstractObserverFactory {...};
class DoThatObserverFactory : AbstractObserverFactory {...};
class DoThisObserverFactory : AbstractObserverFactory {...};
class ObserverParam {...};
class DoThatObserverParam : ObserverParam {...};
class DoThisObserverParam : ObserverParam {...};
class Observer;
class DoThisObserver : public Observer
{
public:
void handlDoThis(DoThisObserverParam);
};