[Insight-developers] Re: [IGSTK-Developers] Observer/Observable pattern

Luis Ibanez luis.ibanez at kitware.com
Sat Feb 24 09:11:23 EST 2007


Hi Ziv,


    Good point.


    It seems that there is a mix of terminology here.



There is the term "Observer" that we usually associate to the
"itk::Command" class. However, there is also the class "Observer"
that is explicitly defined in the itkObject.cxx file in lines 31-45.


There is the "Observable" term, that we usually associate to the
"itk::Object" class and its descendants, but there is also the
itkSubjectImplementation class that is defined in itkObject.cxx
in lines 49-65.



Here is the list of relationships:


itkObject *has one* pointer to an instance of SubjectImplementation.
   itkObject.h line 181.

itkSubjectImplementation has a list of pointers to Observers
   itkObject.cxx line 63:  std::list<Observer* > m_Observers;

itkObserver has a SmartPointer to an itkCommand.
   itkObject.cxx line 42

itkObserver has a raw pointer to an itkEventObject
   itkObject.cxx line 43


The "itkObserver" helper class maintains the association between
an itkCommand and the event that it has declared to be interested
in listening from.



The following diagram may help to illustrate these relationships:


itkObject -----> itkSubjectImplementation
                          |
                          |---> itkObserver ---> itkCommand
                          |
                          |---> itkObserver ---> itkCommand
                          |
                          |---> itkObserver ---> itkCommand
                          |
                          |---> itkObserver ---> itkCommand
                          |
                          |---> itkObserver ---> itkCommand
                          |


When you call itkObject::AddObserver( event, command ) in line
389 of itkObject.cxx, the call is delegated to the SubjectImplementation
AddObserver() method, that is defined in itkObject.cxx lines 80-86.
In this method, an instance of "itkObserver" is created and initialized
with the Event and Command, then pushed into the std::list of Observers
that the SubjectImplementation uses.

The SubjectImplementation class is responsible for the memory of the
"itkObserver" instances, as you can verify in lines 73, 112 and 127;
but it is not directly responsible for the memory of the itkCommand
instances. These last ones are managed simply by the fact that the
instances of itkObserver had a SmartPointer to them.


--


That being said, It seems that the documentation is innacurate on
the aspect of:

    " The memory for the Command becomes the responsibility of
      this object, so don't pass the same instance of a command
      to two different objects"

Since with the current strucutre of code there is no reason why
an instance of an itkCommand couldn't be set as AddObserver()
of multiple itkObjects.




In any case: to differentiate faith and supersition from Truth,
              there is nothing better than an Experiment.



So, please find attached a minimal example of source code
demonstrating that you can use the *same* Command to listen
to more than one different itkObject, and that if one of the
objects is destroyed, the itkCommand is still alive.

The program also demonstrate that a single itkCommand can
listen event from different objects, and differentiate them
based on the itk::Object caller argument of the Execute()
method.


    Please give it a try to this code and let us know
    if you still have any questions.


    We should probably fix the ambiguous
    documentation of the itkObject class.



       Regards,



          Luis





----------------
Ziv Yaniv wrote:
> Luis,
> If what you say is correct then the ITK documentation is wrong.
> This is from the itkObject.h file:
> 
> /** Allow people to add/remove/invoke observers (callbacks) to any ITK
>    * object. This is an implementation of the subject/observer design
>    * pattern. An observer is added by specifying an event to respond to
>    * and an itk::Command to execute. It returns an unsigned long tag
>    * which can be used later to remove the event or retrieve the
>    * command.  The memory for the Command becomes the responsibility of
>    * this object, so don't pass the same instance of a command to two
>    * different objects  */
> 
> That is where I got my many-to-one understanding.
> 
>                   Ziv
> ---------- Original Message ----------------------------------
> From: Luis Ibanez <luis.ibanez at kitware.com>
> Date:  Fri, 23 Feb 2007 18:34:56 -0500
> 
> 
>>Hi Ziv,
>>
>>The Observer pattern in ITK was mostly copied from
>>the functionality existing in VTK at the time.
>>
>>The relationship between Observers and Observables
>>is a many-to-many relationship. That is, and ITK
>>object may have many Observers connected, and a
>>given Observer may be observing many different
>>objects.
>>
>>When an event is invoked, the Execute method of
>>the observer is called. This method include as
>>first argument a pointer to the "caller", which
>>is a pointer to an itkObject.
>>
>>Observable objects *ARE NOT* responsible for the
>>observer memory, not the other way around.
>>
>>What you point out, is rather a weakness in the
>>implementation since the observables are assuming
>>that the observers are still alive by the time the
>>observable invokes an event. This may actually be
>>considered a bug...
>>
>>
>>So,.. there are two independent issues:
>>
>>1) Can Observers observe multiple object ?
>>
>>   The answer is YES.
>>
>>
>>
>>2) Why do observables use a list of raw
>>   pointers instead of SmartPointers ?
>>
>>   The answer is : This can be considered a bug.
>>                   (or at least a weakness...)
>>
>>
>>The fact that (2) uses raw pointers shouldn't be
>>considered as an indication of (1).
>>
>>
>>
>>  Regards,
>>
>>
>>
>>     Luis
>>
>>
>>
>>===================
>>Ziv Yaniv wrote:
>>
>>>Hi All,
>>>
>>>The following question is with regard to ITK, but it spills over to
>>>IGSTK, so I'm sending it to this development list as I'm not on the ITK
>>>developers one.
>>>
>>>I would like to understand the reasoning behind the design of the
>>>ITK observer/observable pattern implementation. According to the
>>>documentation of the AddObserver() method in itk::Object I cannot
>>>have the same Observer attached to several objects, as observable
>>>objects are responsible for the observer's memory. This is
>>>reflected in the use of a raw pointer to a itk::Command object in
>>>the itk::Object::AddObserver() method.
>>>
>>>In the spirit of ITK I expected the AddObserver method to receive
>>>a SmartPointer which also allows a single observer
>>>attached to multiple objects, as the memory would be released
>>>when the last observable deleted its observers.
>>>
>>>Am I missing something? Should this go into a bug/feature request on
>>>the ITK side?
>>>
>>>             regards
>>>                 Ziv
>>>_______________________________________________
>>>IGSTK-Developers mailing list
>>>IGSTK-Developers at public.kitware.com
>>>http://public.kitware.com/cgi-bin/mailman/listinfo/igstk-developers
>>>
>>
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: ObserverMemory.cxx
Type: text/x-c++src
Size: 2492 bytes
Desc: not available
Url : http://www.itk.org/mailman/private/insight-developers/attachments/20070224/c9229212/ObserverMemory.cxx
-------------- next part --------------
# This project is designed to be built outside the Insight source tree.
PROJECT(ObserverMemory)

# Find ITK.
FIND_PACKAGE(ITK REQUIRED)
IF(ITK_FOUND)
  INCLUDE(${ITK_USE_FILE})
ENDIF(ITK_FOUND)

ADD_EXECUTABLE(ObserverMemory ObserverMemory.cxx )

TARGET_LINK_LIBRARIES(ObserverMemory ITKCommon)


More information about the Insight-developers mailing list