Observer Design Pattern

K

Krivenok Dmitry

Hello All!

I am trying to implement my own Design Patterns Library.
I have read the following documentation about Observer Pattern:
1) Design Patterns by GoF
Classic description of Observer. Also describes implementation
via ChangeManager (Mediator + Singleton)
2) Pattern hatching by John Vlissides
Describes Observer's implementation via Visitor Design Pattern.
3) Design Patterns Explained by Alan Shalloway and James Trott
Describes Observer's implementation via Adaptor Design Pattern.
4) CUJ's article : "Prying eyes : A Policy-Based Observer I,II" by
Andrei Alexandrescu
Very interesting articles, which describes attempt to implement
a policy-based Observer and several serious problems:
a) Mutual recursion (potential infinite loops, etc...)
b) Active observers problem (iteration problem)
c) Notification order problem
d) GetState()'s return value problem

I am trying to combine best aspects of each approach.

Consider the following pseudo-code example:

class Subject
{
public:
virtual void Attach(Observer*) = 0;
virtual void Detach(Observer*) = 0;
virtual void Notify() = 0;

virtual @@@ GetState() = 0; // !!! What type should be
returned???
};

class Observer
{
public:
virtual void Update(Subject*) = 0;
};

class MySubject : public Subject
{
public:
void Attach(Observer*)
{
/// Add pair
}
void Detach(Observer*)
{
/// Delete pair
}
void Notify()
{
/// Call observer->Update(this) for each observer in mapping
}

@@@ GetState()
{
/// Return MySubject-specific data. BUT HOW???
}
private:
// Subject-Observer mapping
// MySubject-specific data
};

class YourSubject : public Subject
{
public:
// Along similar lines
private:
// Subject-Observer mapping
// YourSubject-specific data
};

class MyObserver : public Observer /// This class represents MySubject
and YourSubject
{
public:
void Update(Subject* s)
{
/// Only Subject's interface is available here (not MySubject
or YourSubject)
/// I know one bad solution - type switch via dynamic_cast.
if TypeOf(s) == MySubject
{
/// Update MySubject-specific part of representation
}
else if TypeOf(s) == YourSubject
{
/// Update YourSubject-specific part of representation
}
}
private:
/// MyObserver-specific data (e.g. GUI widgets for subjects
representation)
};


The problem lies in poor Subject's interface.
Subject doesn't know anything about MySubject's private data.

I don't understand why GoF includes GetState method in Subject's
interface.
Type of GetState()'s return value depends up concrete subclass of
Subject, i.e.
class ConcreteSubject : Subject
{
public:
ReturnValue<ConcreteSubject> GetState();
...
};

Main question:
How to avoid type switching in ConcreteObserver::Update(Subject* s)?

Thanks!

P.S.
Sorry for my english :)
 
B

boaz_sade

Krivenok said:
Hello All!

I am trying to implement my own Design Patterns Library.
I have read the following documentation about Observer Pattern:
1) Design Patterns by GoF
Classic description of Observer. Also describes implementation
via ChangeManager (Mediator + Singleton)
2) Pattern hatching by John Vlissides
Describes Observer's implementation via Visitor Design Pattern.
3) Design Patterns Explained by Alan Shalloway and James Trott
Describes Observer's implementation via Adaptor Design Pattern.
4) CUJ's article : "Prying eyes : A Policy-Based Observer I,II" by
Andrei Alexandrescu
Very interesting articles, which describes attempt to implement
a policy-based Observer and several serious problems:
a) Mutual recursion (potential infinite loops, etc...)
b) Active observers problem (iteration problem)
c) Notification order problem
d) GetState()'s return value problem

I am trying to combine best aspects of each approach.

Consider the following pseudo-code example:

class Subject
{
public:
virtual void Attach(Observer*) = 0;
virtual void Detach(Observer*) = 0;
virtual void Notify() = 0;

virtual @@@ GetState() = 0; // !!! What type should be
returned???
};

class Observer
{
public:
virtual void Update(Subject*) = 0;
};

class MySubject : public Subject
{
public:
void Attach(Observer*)
{
/// Add pair
}
void Detach(Observer*)
{
/// Delete pair
}
void Notify()
{
/// Call observer->Update(this) for each observer in mapping
}

@@@ GetState()
{
/// Return MySubject-specific data. BUT HOW???
}
private:
// Subject-Observer mapping
// MySubject-specific data
};

class YourSubject : public Subject
{
public:
// Along similar lines
private:
// Subject-Observer mapping
// YourSubject-specific data
};

class MyObserver : public Observer /// This class represents MySubject
and YourSubject
{
public:
void Update(Subject* s)
{
/// Only Subject's interface is available here (not MySubject
or YourSubject)
/// I know one bad solution - type switch via dynamic_cast.
if TypeOf(s) == MySubject
{
/// Update MySubject-specific part of representation
}
else if TypeOf(s) == YourSubject
{
/// Update YourSubject-specific part of representation
}
}
private:
/// MyObserver-specific data (e.g. GUI widgets for subjects
representation)
};


The problem lies in poor Subject's interface.
Subject doesn't know anything about MySubject's private data.

I don't understand why GoF includes GetState method in Subject's
interface.
Type of GetState()'s return value depends up concrete subclass of
Subject, i.e.
class ConcreteSubject : Subject
{
public:
ReturnValue<ConcreteSubject> GetState();
...
};

Main question:
How to avoid type switching in ConcreteObserver::Update(Subject* s)?

Thanks!

P.S.
Sorry for my english :)

Maybe you should try to avoid reading to many design books. You can
start by forgeting everything you read in the GoF book (unless you
interested in making your life as programmer harder and your code more
complicated)
 
J

Jeff Flinn

[snipped code]
Maybe you should try to avoid reading to many design books. You can
start by forgeting everything you read in the GoF book (unless you
interested in making your life as programmer harder and your code
more complicated)

Maybe you could back that up with some specific instances?

Jeff Flinn
 
D

Daniel T.

Krivenok said:
Hello All!

I am trying to implement my own Design Patterns Library.

You can't do that in general. Design Patterns are at a level higher
than simple code reuse. That said...

The classic "pull model" can be implemented like this:

class Observer
{
public:
virtual ~Observer() { }
virtual void update() = 0;
};

class Subject
{
std::set< Observer* > observers;
public:
void attach( Observer* o ) {
observers.insert( o );
}

void detach( Observer* o ) {
observers.erase( o );
}

void notify() {
for_each( observers.begin(), observers.end(),
mem_fun( &Observer::update ) );
}
};


class MySubject : public Subject
{
int state;
public:
int getState() const { return state; }
void setState( int value ) { state = value; notify(); }
};

class MyObserver : public Observer
{
MyObserver( const MyObserver& );
MyObserver& operator=( const MyObserver& );

MySubject* subject;

public:
MyObserver( MySubject* subject_ ): subject( subject_ ) {
subject->attach( this );
}

~MyObserver() {
subject->detach( this );
}

void update() {
// do something with subject->getState();
}
};

However, I have found the "push model" to be much more useful:

template < typename Observer >
class Subject {
std::set< Observer* > observers;

public:
void attach( Observer* o ) {
observers.insert( o );
}

void detach( Observer* o ) {
observers.erase( o );
}

template < typename ConcreteSubject >
void notify( const ConcreteSubject* cs, void (Observer::*fn)( const
ConcreteSubject* ) ) {
std::set< Observer* >::iterator it = observers.begin();
while ( it != observers.end() ) {
Observer* ob( *it++ );
(ob->*fn)( cs );
}
}
};
I don't understand why GoF includes GetState method in Subject's
interface.

They did that because they were looking at SmallTalk examples which
didn't translate well to C++
Main question:
How to avoid type switching in ConcreteObserver::Update(Subject* s)?

As I showed above.
 
J

Joe Van Dyk

Daniel said:
You can't do that in general. Design Patterns are at a level higher
than simple code reuse. That said...

I'm not sure what you mean by this. Can you elaborate?

Joe
 
J

Joe Van Dyk

Krivenok said:
Hello All!

I am trying to implement my own Design Patterns Library.
I have read the following documentation about Observer Pattern:
1) Design Patterns by GoF
Classic description of Observer. Also describes implementation
via ChangeManager (Mediator + Singleton)
2) Pattern hatching by John Vlissides
Describes Observer's implementation via Visitor Design Pattern.
3) Design Patterns Explained by Alan Shalloway and James Trott
Describes Observer's implementation via Adaptor Design Pattern.
4) CUJ's article : "Prying eyes : A Policy-Based Observer I,II" by
Andrei Alexandrescu
Very interesting articles, which describes attempt to implement
a policy-based Observer and several serious problems:
a) Mutual recursion (potential infinite loops, etc...)
b) Active observers problem (iteration problem)
c) Notification order problem
d) GetState()'s return value problem

I am trying to combine best aspects of each approach.

You might want to try out "Head First Design Patterns". Pretty decent book.

Joe
 
J

Jeremy Jurksztowicz

You can't do that in general. Design Patterns are at a level higher
I'm not sure what you mean by this. Can you elaborate?

I think what he means is that the patterns in the GoF book are not code
patterns per se, in that they were not meant to be reused as a unit of
code, but rather DESIGN patterns, which you could use to solve common
design problems. In other words, you may have to write and modify the
pattern code from scratch to solve the coding problem, but the design
problem is addressed by the design pattern you select.

This is somewhat subtle, especially in C++ where generic programming
has such a foothold. Often times we want to make an ideal instance of a
pattern in highly reusable C++ code. I think this is a great idea, even
if only for practices sake.
 
B

boaz_sade

Jeff said:
[snipped code]
Maybe you should try to avoid reading to many design books. You can
start by forgeting everything you read in the GoF book (unless you
interested in making your life as programmer harder and your code
more complicated)

Maybe you could back that up with some specific instances?

Jeff Flinn
To be more specific will take too mach of my time bust generaly I think
that in many of those advice books (not just in programming books) they
think that the have those silver bults that they discovor and now its
their job to convince you that once you will use them you can "kill"
all of your problems with them. Take for exaple the books about "how to
become rigch in X days" - do you really belive that by following their
advices you will become richer - if you do then by all means you can
coninue along this road. Presonlly I don't think (coming back to
programmning) that someone who don't know my system, the truble I have
implementing it and that I don't know too mach about him/her eigher can
give me solutions. If I need advice I will at least let my advicer see
my personl problem then I belive that he/she can truly help me. Anther
thing is - reading those books give you the impration that those people
never really wrote production code and their solutions are to academic
 
D

Dave Steffen

Jeremy Jurksztowicz said:
I think what he means is that the patterns in the GoF book are not code
patterns per se, in that they were not meant to be reused as a unit of
code, but rather DESIGN patterns, which you could use to solve common
design problems. In other words, you may have to write and modify the
pattern code from scratch to solve the coding problem, but the design
problem is addressed by the design pattern you select.

Precisely. I recomment that the OP head directly to "Modern C++
Design" by Alexandrescu. Most of that book is generic implementations
of design patterns.
This is somewhat subtle, especially in C++ where generic programming
has such a foothold. Often times we want to make an ideal instance
of a pattern in highly reusable C++ code. I think this is a great
idea, even if only for practices sake.

And extremely difficult, as anyone who has read Alexandrescu (or
looked at the various Boost libraries that do similar things) can
attest.

----------------------------------------------------------------------
Dave Steffen, Ph.D. Fools ignore complexity.
Software Engineer IV Pragmatists suffer it.
Numerica Corporation Some can avoid it.
ph (970) 419-8343 x27 Geniuses remove it.
fax (970) 223-6797 -- Alan Perlis
dgsteffen at numerica dot us
 
J

Jeff Flinn

Jeff said:
Krivenok Dmitry wrote:
Hello All!

I am trying to implement my own Design Patterns Library.
I have read the following documentation about Observer Pattern:
1) Design Patterns by GoF
Classic description of Observer. Also describes implementation
via ChangeManager (Mediator + Singleton)
2) Pattern hatching by John Vlissides
Describes Observer's implementation via Visitor Design Pattern.
3) Design Patterns Explained by Alan Shalloway and James Trott
Describes Observer's implementation via Adaptor Design Pattern.
4) CUJ's article : "Prying eyes : A Policy-Based Observer I,II" by
Andrei Alexandrescu
Very interesting articles, which describes attempt to implement
a policy-based Observer and several serious problems:
a) Mutual recursion (potential infinite loops, etc...)
b) Active observers problem (iteration problem)
c) Notification order problem
d) GetState()'s return value problem

I am trying to combine best aspects of each approach.

Consider the following pseudo-code example:

[snipped code]
Main question:
How to avoid type switching in ConcreteObserver::Update(Subject*
s)?

Maybe you should try to avoid reading to many design books. You can
start by forgeting everything you read in the GoF book (unless you
interested in making your life as programmer harder and your code
more complicated)

Maybe you could back that up with some specific instances?

Jeff Flinn
To be more specific will take too mach of my time bust generaly I

[snipped baseless opinion]

How about focusing on just Design Patterns by GoF?

Jeff Flinn
 
B

boaz_sade

Jeff said:
Jeff said:
(e-mail address removed) wrote:
Krivenok Dmitry wrote:
Hello All!

I am trying to implement my own Design Patterns Library.
I have read the following documentation about Observer Pattern:
1) Design Patterns by GoF
Classic description of Observer. Also describes implementation
via ChangeManager (Mediator + Singleton)
2) Pattern hatching by John Vlissides
Describes Observer's implementation via Visitor Design Pattern.
3) Design Patterns Explained by Alan Shalloway and James Trott
Describes Observer's implementation via Adaptor Design Pattern.
4) CUJ's article : "Prying eyes : A Policy-Based Observer I,II" by
Andrei Alexandrescu
Very interesting articles, which describes attempt to implement
a policy-based Observer and several serious problems:
a) Mutual recursion (potential infinite loops, etc...)
b) Active observers problem (iteration problem)
c) Notification order problem
d) GetState()'s return value problem

I am trying to combine best aspects of each approach.

Consider the following pseudo-code example:

[snipped code]

Main question:
How to avoid type switching in ConcreteObserver::Update(Subject*
s)?

Maybe you should try to avoid reading to many design books. You can
start by forgeting everything you read in the GoF book (unless you
interested in making your life as programmer harder and your code
more complicated)

Maybe you could back that up with some specific instances?

Jeff Flinn
To be more specific will take too mach of my time bust generaly I

[snipped baseless opinion]

How about focusing on just Design Patterns by GoF?

Jeff Flinn
Ok -
The itterator design pattern they have is the worse way to do it - we
all should be thankful that STL Spetanv did not take their idea but
rather use a different much better way of doing it.
Next their Template and Algorithm patterns - do you really think that
we need those?
The factor pattern is anther jock - you can do it so much simpler using
templates that it's becoming about 2 line of code without paying
runtime overhead and writing so elaborated pattern.
I can continue with more examples but its becoming boring. With today
techniques (using generative/meta programming) and with the overhead
costs that their pattern are panelizing you with why bather? In any
case I think that their 2 worst traits are:
1. Complexity - any complex solution is a poor one. Its indication of
too much design or not enough.
2. It become irrelevant - this book was writing in the days when GUI
programming was the hot topic (we have Java out of it to..), but
writing GUI with C++, I really think that anyone doing it should
consider a different profession
 
T

Thomas J. Gritzan

Ok -
The itterator design pattern they have is the worse way to do it

Whats the problem with it?
Next their Template and Algorithm patterns - do you really think that
we need those?

The Template design pattern is used in the STL all over the place:

std::sort, std::copy, ...
The factor pattern is anther jock - you can do it so much simpler using
templates that it's becoming about 2 line of code without paying
runtime overhead and writing so elaborated pattern.
How?

2. It become irrelevant - this book was writing in the days when GUI
programming was the hot topic (we have Java out of it to..), but
writing GUI with C++, I really think that anyone doing it should
consider a different profession

Whats wrong with writing GUI in C++? I guess I should consider a
different profession, too.

Thomas
 
T

Thomas J. Gritzan

Thomas said:
The Template design pattern is used in the STL all over the place:

std::sort, std::copy, ...

Err, not std::copy.

Used in:

std::sort, std::for_each, std::find_if, std::transform and the like...

Thomas
 
B

boaz_sade

Thomas said:
Err, not std::copy.

Used in:

std::sort, std::for_each, std::find_if, std::transform and the like...

Thomas
Then eigher you don't know how those algorithms are implemented, or you
don't know the algorithm design pattern from the GoF book - take you
pick :)
There is NO correlation between the STL and design pattern GoF. If you
read Spetanov opinion about design you will not even think that he even
read this useless book
 
B

boaz_sade

Dave said:
Precisely. I recomment that the OP head directly to "Modern C++
Design" by Alexandrescu. Most of that book is generic implementations
of design patterns.


And extremely difficult, as anyone who has read Alexandrescu (or
looked at the various Boost libraries that do similar things) can
attest.

----------------------------------------------------------------------
Dave Steffen, Ph.D. Fools ignore complexity.
Software Engineer IV Pragmatists suffer it.
Numerica Corporation Some can avoid it.
ph (970) 419-8343 x27 Geniuses remove it.
fax (970) 223-6797 -- Alan Perlis
dgsteffen at numerica dot us
Alexandrescu book is nice (not to diffecult to read) and full with
implemetation that you will never use in real code and that in many
cases you can implement yourself with metaprogramminhg mach better if
you understand metaprogramming. In the boost lib there is no attempt to
implement design pattern from the GoF book and this is why is a usefull
lib that you can pick good things out of it. The main thing that you
should consider when using other's code is whether this code don't
place more overhead then stright implemention (this is why there is no
virtual devertion in the STL, so it will not place run time overhead)
and whether you make the code simpler to use. As mach as I have simpaty
with Alexandrescu book I don't thing that the code in his book is
really usefull (and again I don't think that its too hard to understand
what he doning there, just that its has to mach runtime overhead or/and
that he makes simple cases to complicated)
 
B

boaz_sade

Dave said:
Precisely. I recomment that the OP head directly to "Modern C++
Design" by Alexandrescu. Most of that book is generic implementations
of design patterns.


And extremely difficult, as anyone who has read Alexandrescu (or
looked at the various Boost libraries that do similar things) can
attest.

----------------------------------------------------------------------
Dave Steffen, Ph.D. Fools ignore complexity.
Software Engineer IV Pragmatists suffer it.
Numerica Corporation Some can avoid it.
ph (970) 419-8343 x27 Geniuses remove it.
fax (970) 223-6797 -- Alan Perlis
dgsteffen at numerica dot us

Fools ignore complexity.
Pragmatists suffer it.
Some can avoid it.
Geniuses remove it.
If you really think that this is true then I think that you to should
think that unneeded complixity should be avoided at all cost, and those
design pattern are the exct case where unneeded complexity is used
 
B

boaz_sade

Thomas said:
Whats the problem with it?


The Template design pattern is used in the STL all over the place:

std::sort, std::copy, ...


Whats wrong with writing GUI in C++? I guess I should consider a
different profession, too.

Thomas
Why using C++ to write GUI for what do you gain by using this language?
Did you ever read "the C++ programming language" book? At the first
page Stroupsrup himself say:
"Each style can achieve its aims effectively while maintaining run-time
and space efficiency." If think that anyone clicking buttons in the
screen can feel the difference between useconds and mseconds of respond
time (meaning - it was writing in VB, Java or C# or that it's more
efficient because it was writing in C++ then good luck). The main thing
when writing production code (not toying with programs that no one will
use) is that you want to use a tool that will let you do it with the
least unneeded work and with as little bugs as possible. Why not using
a programming language that was design to support something instead of
developing something yourself just so you will start a cycle of design
-> implement -> debug -> QA -> design... If I have someone else's doing
this work for me why not using their tool. The best example is MFC vs.
VB, With MFC you have to write a lot of code find that the MFC itself
is full for bugs that there is no good support for MT and that you
cannot even use many C++ technique since it was basically was writing
over C code - and what do you gain out of it. By the time you finish
doing one dialog in MFC you can finish shipping you product in VB. And
I'm talking out of experience. I rather use C++ where I really need it
strength and not explore its weaknesses
 
D

Daniel T.

Then eigher you don't know how those algorithms are implemented, or you
don't know the algorithm design pattern from the GoF book - take you
pick :)

He got the latter wrong. sort, for_each, find_if, transform, &c. are
all examples of the Strategy pattern.
There is NO correlation between the STL and design pattern GoF.

Either you don't understand design patterns or you don't know the STL,
take your choice. :) Actaully, I don't think you do get to choose. You
look at the implementations in the Design Patterns book and assume that
they are saying that those are the only way to implement them and
that's just plain wrong. That's why I told the OP that implementing a
"Design Pattern Library" can't be done in general. There are too many
different ways to implement the patterns discussed.

Even with a pattern as simple as Observer, I showed two completely
different ways to implement (one using runtime polymorphism and a pull
approach, one using tempates and a push approach.)

The Iterator pattern is fundimental to STL and as I show above,
Strategy is used all over the place as well.

Based on one of your other posts, you don't seem to think that STL uses
Iterator. You need to broaden your mind and look again.

GoF Iterator C++ Iterator
First() it = container.begin()
Next() operator++()
IsDone() it == container.end()
CurrentItem() *it
 
D

Diego Martins

Daniel said:
He got the latter wrong. sort, for_each, find_if, transform, &c. are
all examples of the Strategy pattern.


Either you don't understand design patterns or you don't know the STL,
take your choice. :) Actaully, I don't think you do get to choose. You
look at the implementations in the Design Patterns book and assume that
they are saying that those are the only way to implement them and
that's just plain wrong. That's why I told the OP that implementing a
"Design Pattern Library" can't be done in general. There are too many
different ways to implement the patterns discussed.

Even with a pattern as simple as Observer, I showed two completely
different ways to implement (one using runtime polymorphism and a pull
approach, one using tempates and a push approach.)

The Iterator pattern is fundimental to STL and as I show above,
Strategy is used all over the place as well.

Based on one of your other posts, you don't seem to think that STL uses
Iterator. You need to broaden your mind and look again.

GoF Iterator C++ Iterator
First() it = container.begin()
Next() operator++()
IsDone() it == container.end()
CurrentItem() *it

very good post :)

now, all is clear to me about this thread

I was thinking the "boaz" was an ENGRISH troll with his opinion already
formed (ill-formed) about GoF patterns

but now, I see the "boaz" was using the GoF patterns like strict APIs

design patterns are ideas. annotated and discussed ideas.

honest :)
 

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

Forum statistics

Threads
473,968
Messages
2,570,149
Members
46,695
Latest member
StanleyDri

Latest Threads

Top