Re: Observer Design Pattern
- From: Robert Martin <unclebob@xxxxxxxxxxxxxxxx>
- Date: Wed, 31 May 2006 07:32:45 -0500
On 2006-05-31 06:00:00 -0500, "Krivenok Dmitry" <dima@xxxxxxxxxxxxxxxxxx> said:
Hello All!
I am trying to implement my own Design Patterns Library.
If you are talking about a code library (as opposed to a library of documents) then I'd like to discourage you. Design Patterns are not the kind of thing that you can turn into a reusable coding library.
Observer is one of the exceptions to this rule; but it's only a partial exception for the reasons that you have already pointed out in your post.
I have included some comments below..
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???
};
This is the problem with making Observer part of a reusable library. There is no good option for GetState. I usually omit it entirely. See below.
class Observer
{
public:
virtual void Update(Subject*) = 0;
};
I usually don't pass the Subject* to the Observer. I like my observers to attach to one, and only one, subject. This is just my particular style and I wouldn't make it a hard and fast rule. But read on.
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???
}
Again, this is not usually feasible in statically typed languages like C++. You could pass a void* and then reinterpret_cast it; but that's hideous. Read on.
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
}
I don't want my observers to have to switch on types. Each of my observers knows the type of the object it is observing. Indeed, since I only have one observer per subject, my observers know exactly which object they are observing.
I would be willing to relax the later rule, but not the former. Even if my observers observed more than one object at a time; I would make sure that all those subjects were of the same type. Therefore I could safely downcast the Subject* to MySubject*.
}
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.
Yes, that is the problem; and there is no general solution for it. You can use templates to create a Subject<MyData> and Observer<MyData> but I find this to be overkill. The simple rule of one-subject/one-observer solves most of these problems.
I don't understand why GoF includes GetState method in Subject's
interface.
That was just an illustration, not a mandatory function. In a "pull-model" observer every subject will have some function(s) that allow the observer to get the state.
Main question:
How to avoid type switching in ConcreteObserver::Update(Subject* s)?
One-subject/one-observer.
Thanks!
P.S.
Sorry for my english :)
Your english was fine.
--
Robert C. Martin (Uncle Bob) | email: unclebob@xxxxxxxxxxxxxxxx
Object Mentor Inc. | blog: www.butunclebob.com
The Agile Transition Experts | web: www.objectmentor.com
800-338-6716 |
.
- Follow-Ups:
- Re: Observer Design Pattern
- From: Joe Van Dyk
- Re: Observer Design Pattern
- References:
- Observer Design Pattern
- From: Krivenok Dmitry
- Observer Design Pattern
- Prev by Date: Re: Observer Design Pattern
- Next by Date: Re: The wisdom of the object mentors (Was: Searching OO Associations with RDBMS Persistence Models)
- Previous by thread: Re: Observer Design Pattern
- Next by thread: Re: Observer Design Pattern
- Index(es):
Relevant Pages
|