Generalized "observer" pattern

G

Gianni Mariani

Two issues here:

a) What is the accepted definition of "observer pattern". While I can't
point to anything specific, I do remember having issues with
inconsistency in the definition.

b) Generic observer design in C++. I have been pushing the Austria
"Twin" interface for a while and more recently the multi threaded
version of it "TwinMT" (see the 6129 alpha on sourceforge)

I am trying to distill the "fundamental" hard problems in software
development, especially regarding C++ and I've seen too many issues
relating to the observer pattern I think it is elevated to "fundamental".

By fundamental issues I mean, "avoiding deadlock conditions", object
lifetime management etc.

There is no specific question really, just an invitiation for thoughts
on the topic.
 
W

werasm

Gianni said:
Two issues here:

a) What is the accepted definition of "observer pattern". While I can't
point to anything specific, I do remember having issues with
inconsistency in the definition.

I'm not sure I know what you mean by accepted definition. Interface
Specification?

e.g:

Subject:
Register: Observer.
Unregister: Observer.
Update: State

Observer:
Notify: State

Wikipedia has an interface specification. Whether this is accepted is
another
question, but it is based on the original GOF pattern.

There are also a couple of variations.

Push/Pull: Do you push the data during notification, or do each of the
observers
have an interface to the subject, pulling data after notification.

Aspect: Observers could register for interests in specific aspects. I
don't like this,
though, as I prefer an observer interface per aspect e.g. If you have
a new aspect,
you have a new "Twin" as you would call it.
b) Generic observer design in C++. I have been pushing the Austria
"Twin" interface for a while and more recently the multi threaded
version of it "TwinMT" (see the 6129 alpha on sourceforge)

I have briefly seen it in the past, yes. Will have to look again as it
was
not recent.
I am trying to distill the "fundamental" hard problems in software
development, especially regarding C++ and I've seen too many issues
relating to the observer pattern I think it is elevated to "fundamental".

One of the things we have done in our subject/observer pairs, is to
have
no coupling between the subject and observer, but the subject just
dispatches the data that is of interest. Notify then becomes
notify( data ) instead of notify( observer ). This is especially
beneficial (IMO) in a MT environment to prevent coupling of
observers in other threads.

Obviously unsubscription especially does cause thread coupling,
but I've found that that only takes place during deletion, often only
at the end of the program when only on tread of execution exists.
I'm very conservative wrt. this. IMO it's better to ensure that your
application framework starts/stops in a controlled way than to cater
for the worse case. The caveats obviously need to be documented.

Another issue is whether to us RAII as subscription/unsubscription
mechanism. This can reduce lots of coding, but in certain cases
can be dangerous (and actually, if you want to be exception safe,
its probably necessary). The dangerous cases are when you have
circular observers, so to speak. A subject observers another subject
and visa versa. Keeping a weak pointer to the Subject that the
observer is associated with solves this easy, though. Usually my
observer lists are normal pointers, whilst for the association:

Observer -> Subject

I use a weak pointer so that the observer does not detach from
a non-existent subject. I find that the circular dependency in this
case can be quite common. Also, subscription/unsubscription
take place much less often than notification, therefore having
a weak pointer for this relationship makes sense.

Regards,

Werner
 
W

werasm

Gianni said:
a) What is the accepted definition of "observer pattern". While I can't
point to anything specific, I do remember having issues with
inconsistency in the definition.

Aside, and probably OT, I've written a little generic class that
performs
RAII subscription/unsubsription. I attempted to make it definition
independent, handling either attach/detach, subscribe/unsubscribe or
add/remove as potential interface. It was merely a nice exercise for
SFINAE (and credit to some posts in c.l.c++, as well as boost
archives).

CAVEAT: Does not use weak pointer yet as described in my other
mail. I just at the time of writing this have not thought of that
problem
yet.

Here goes:

namespace AviGen {
namespace GenSubPriv{

typedef char (&subscribe)[0];
typedef char (&add)[1];
typedef char (&attach)[2];
template < typename T, void (T::*)() >
struct ptmf_helper {};

template< typename T > subscribe get_method_literal( ... ); //
Subscribe
template< typename T > add
get_method_literal( ptmf_helper<T,&T::add>* );
template< typename T > attach
get_method_literal( ptmf_helper<T,&T::attach>* );

template <class PubT, class SubT, std::size_t>
class GenSubBase;

// Used subscribe/unsubscribe to subscribe.
template <class PubT, class SubT>
class GenSubBase<PubT, SubT, sizeof(subscribe)> : public SubT
{
protected:
GenSubBase( PubT& publisher ): publisher_( publisher )
{ publisher_.subscribe( *this ); }
virtual ~GenSubBase()
{ publisher_.unsubscribe( *this ); }
private:
PubT* publisher_;
};

// Used add/remove to subscribe.
template <class PubT, class SubT>
class GenSubBase<PubT, SubT, sizeof(add)> : public SubT
{
protected:
GenSubBase( PubT& publisher ): publisher_( publisher )
{ publisher_.add( *this ); }
virtual ~GenSubBase()
{ publisher_.remove( *this ); }
private:
PubT* publisher_;
};

// Used attach/detach to subscribe.
template <class PubT, class SubT>
class GenSubBase<PubT, SubT, sizeof(attach)> : public SubT
{
protected:
GenSubBase( PubT& publisher ): publisher_( publisher )
{ publisher_.attach( *this ); }
virtual ~GenSubBase()
{ publisher_.detach( *this ); }
private:
PubT* publisher_;
};

}//end namespace GenSubPriv

//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Author : werasmus
// Date : Sep 22, 2007 7:41:39 PM
// Description:
// This class provides the ability to subscribe/unsubscribe in a RAII
fashion.
// Currently it caters for the publisher to outlive the subscriber,
hence the
// publisher is accepted as reference in the constructor.
// Note:
// Currently works for Publishers with interface <add/remove>, <attach/
detach> and
// <subscribe/unsubscribe>.
// TODO:
// We could modify the publisher member iaw. a policy at later stage,
the default
// probably being weak pointer.
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
template <class PubT, class SubT>
class GenSubscriber
: public GenSubPriv::GenSubBase<PubT,
SubT,sizeof(GenSubPriv::get_method_literal<PubT>(0))>
{
protected:
typedef typename GenSubPriv::GenSubBase<PubT,
SubT,sizeof(GenSubPriv::get_method_literal<PubT>(0))> Base;
//_____________ operations _____________//
GenSubscriber( PubT& publisher ): Base( publisher ){ }
};
 
J

James Kanze

Two issues here:
a) What is the accepted definition of "observer pattern".
While I can't point to anything specific, I do remember having
issues with inconsistency in the definition.

I don't know if there is anything really formal, but I'd tend to
go with the description in the GoF book, if only because it
seems to be the most widespread.
b) Generic observer design in C++. I have been pushing the Austria
"Twin" interface for a while and more recently the multi threaded
version of it "TwinMT" (see the 6129 alpha on sourceforge)

I'm not sure, but "Twin" sounds like you're managing a
one-to-one relationship. In my experience, it's almost always a
1->n relationship: each Observable will have many Observer.
I am trying to distill the "fundamental" hard problems in
software development, especially regarding C++ and I've seen
too many issues relating to the observer pattern I think it is
elevated to "fundamental".
By fundamental issues I mean, "avoiding deadlock conditions",
object lifetime management etc.

And persistency?

You're not the first. Back in the early 1990's, there was a lot
of discussion of "relationship management", with the hope of
finding some nice generic solution. As far as I know, there
were no real useful results, but the issue still seems to be
considered important---Java's hyping "container-managed
relations" in EJB.
 
G

Guest

Two issues here:

a) What is the accepted definition of "observer pattern". While I can't
point to anything specific, I do remember having issues with
inconsistency in the definition.

I would assume that it is the one given in the GoF book, if you do not
have it the wikipedia article is more or less a copy from the book,
especially the "Participant classes" section.
b) Generic observer design in C++. I have been pushing the Austria
"Twin" interface for a while and more recently the multi threaded
version of it "TwinMT" (see the 6129 alpha on sourceforge)

I am trying to distill the "fundamental" hard problems in software
development, especially regarding C++ and I've seen too many issues
relating to the observer pattern I think it is elevated to "fundamental".

I do not see how there can any issues with the observer pattern, it is
very simple, however I perhaps not very useful either. I prefer a more
advanced version (I am sure this is some pattern but I do not know its
name) where the observing class is not only informed that something has
happened, but also what. So instead of just having a notify() function
the observing class has a onFoo(Bar& sender, FooArgs arguments) function
that tells the observing class what happened (the arguments) and to whom
(the sender). Anyone know the name of this pattern?
 
W

werasm

Erik Wikström wrote:

not see how there can any issues with the observer pattern, it is
very simple, however I perhaps not very useful either. I prefer a more
advanced version (I am sure this is some pattern but I do not know its
name) where the observing class is not only informed that something has
happened, but also what. So instead of just having a notify() function
the observing class has a onFoo(Bar& sender, FooArgs arguments) function
that tells the observing class what happened (the arguments) and to whom
(the sender). Anyone know the name of this pattern?

Aspect observer, perhaps? Notify( aspect) or Notify( state ). But
our observers only tend to observer a very concise aspect. One
could register for notification wrt. a particular concern or aspect.

Register: Observer. // where the observer has interface GetAspect.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top