[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

custom callback handlers

Posted on 2012-08-12
9
Medium Priority
?
439 Views
Last Modified: 2012-09-13
Hello experts.  Consider the snippet below which compiles and runs.

# include <iostream>

# include <boost/scoped_ptr.hpp>
# include <boost/shared_ptr.hpp>

# include <boost/function.hpp>
# include <boost/array.hpp>
# include <boost/asio.hpp>
# include <boost/thread.hpp>
# include <boost/thread/locks.hpp>
# include <boost/bind.hpp>
# include <boost/noncopyable.hpp>


class DataLink {};
class Metadata {};
class Image {};

 typedef boost::function<void( DataLink const&, Metadata const& , Image const& )> Handler ; 
 typedef boost::function<void( Metadata const& , Image const& )> Handler2 ; 
 typedef boost::function<void( Image const& )> Handler3 ; 

enum callbackHandler { link_enum, meta_enum, image_enum };
class Worker {
  Handler  callBack ;
  //Handler2 callBack2 ;
  //Handler3 callBack3 ;

  DataLink dlink;
  Metadata meta ;
  Image    img ;

  callbackHandler handlerEnum ;

public :
  Worker ( const Handler& handler ) 
  : callBack ( handler ) 
   {}
  //Worker ( const Handler2& handler ) 
  //: callBack2 ( handler ) 
  // {}
  //Worker ( const Handler3& handler ) 
  //: callBack3 ( handler ) 
  // {}

  void Image ( ) {
	// update the img object 
	// invoke call back 
    handlerEnum = image_enum ;
    callBack ( dlink, meta, img ) ;
  }

  void Metadata ( ) {
	// update the meta object 
	// invoke call back 
    handlerEnum = meta_enum ;
    callBack ( dlink, meta, img ) ;
  }

  void Dlink ( ) {
	// update the link object 
	// invoke call back 
    handlerEnum = link_enum ;
    callBack ( dlink, meta, img ) ;
  }

  callbackHandler getHandlerType() { return handlerEnum ; }
};


class Foo {
  Worker *ptrWorker ;
public :
  Foo () 
  : ptrWorker( 0 ) 
  {}

  void callback ( DataLink const& d, Metadata const& m , Image const&  i ) {
    callbackHandler tt = ptrWorker->getHandlerType();
    if ( tt == image_enum ) {
      std::cout <<  "Image object " << std::endl;
    }
    if ( tt == meta_enum ) {
      std::cout <<  "Meta object " << std::endl;
    }
    if ( tt == link_enum ) {
      std::cout <<  "Link object " << std::endl;
    }

  }
  bool start () {
    ptrWorker = new ( std::nothrow ) Worker ( boost::bind ( &Foo::callback, this, _1, _2, _3 ) );
    if ( !ptrWorker ) {
      return - 1 ;
    }
  }
  void testWorker() {
    ptrWorker->Image() ;
    ptrWorker->Metadata() ;
    ptrWorker->Dlink() ;
  }
};

int main() {
  Foo f;
  f.start() ;
  f.testWorker() ;

}

Open in new window


The commented out constructors allows me to add support for Handler2 and Handler3, however is there a way to determine the handler that was passed to the constructor of the Worker class?   At present the member functions Metadata, Image and Dlink use the 'callBack' object.  I'll need to make a distinction if the user handler passed in another handler - say Handler2.

Worse case, I'm open to revising the code so by all means I'm open to an alternative (demonstrate with sample source).  My itent is to have 4 handlers clients could choose from but I'd like to know which handler was instatiated. and invoke the appropriate one.
0
Comment
Question by:forums_mp
  • 5
  • 3
9 Comments
 
LVL 36

Expert Comment

by:mccarl
ID: 38286218
Is there any reason why you wouldn't just create 3 different Worker classes? Say ImageWorker, MetadataWorker, and DlinkWorker that handle the different callbacks. If there truly is common code somehow to those 3 classes then they could inherit from a base Worker class that contains that common code.

It is a bit hard to provide sample code, as it is unclear to me exactly what you are trying to achieve here with the code that you have.
0
 
LVL 40

Assisted Solution

by:evilrix
evilrix earned 600 total points
ID: 38290103
Hi forums_mp.



Hmmm. Having to have N-1 dummy handlers (ie, at any one time only one handler is being used and the others are just there doing nothing) defined in the class screams confused and low cohesive object model. The fact you need to use enums to implement, what is effectively your own type-system (in the line of a discrimatory union - aka, a variant), is also a sure sign that the design needs a little re-thinking.

I tend to agree with mccarl... at least in principle. There are a number of ways to tackle this but assuming you want to try and keep the original design premise as intact as possible you could make worker a template class, with the template parameter being that of the Handler type? Since you'll then know the static type of the handler you can use the type system to handle the different scenarios.

Put another way, using static polymorphism (templates) you can probably do what you are trying to do with; using specialisation to handle the dissimilarities of each worker type.

Something like (very quick and dirty hack):

# include <iostream>

# include <boost/scoped_ptr.hpp>
# include <boost/shared_ptr.hpp>

# include <boost/function.hpp>
# include <boost/array.hpp>
# include <boost/asio.hpp>
# include <boost/thread.hpp>
# include <boost/thread/locks.hpp>
# include <boost/bind.hpp>
# include <boost/noncopyable.hpp>


class DataLink {};
class Metadata {};
class Image {};

typedef boost::function<void( DataLink const&, Metadata const& , Image const& )> LinkHandler;
typedef boost::function<void( Metadata const& , Image const& )> MetaHandler;
typedef boost::function<void( Image const& )> ImageHandler;

template <typename HandlerT>
class Worker_ {
   typedef HandlerT handler_type;
   handler_type  callBack ;

   DataLink dlink_;
   Metadata meta_ ;
   Image    img_ ;

   public :
   Worker_ ( const handler_type& handler )
      : callBack ( handler )
   {}

   /* you'll probably need to specialise these for different worker types */
   void image ( ) {
      //callBack ( dlink, meta, img ) ;
   }

   void metadata ( ) {
      //callBack ( dlink, meta, img ) ;
   }

   void dlink ( ) {
      //callBack ( dlink, meta, img ) ;
   }
};

typedef Worker_<LinkHandler> LinkWorker;
typedef Worker_<MetaHandler> MetaWorker;
typedef Worker_<ImageHandler> ImageWorker;

void handler_distinction(ImageWorker const * ptrWorker)
{
   std::cout <<  "Image object " << std::endl;
}

void handler_distinction(MetaWorker const * ptrWorker)
{
   std::cout <<  "Meta object " << std::endl;
}

void handler_distinction(LinkWorker const * ptrWorker)
{
   std::cout <<  "Link object " << std::endl;
}

template <typename WorkerT>
class Foo {
   typedef WorkerT worker_type;

   worker_type *ptrWorker ;
   public :
   Foo ()
      : ptrWorker( 0 )
   {}

   void callback ( DataLink const& d, Metadata const& m , Image const&  i ) {
      handler_distinction(ptrWorker);
   }
   bool start () {
      /* you'll need to specialise this for different worker types
      ptrWorker = new ( std::nothrow ) worker_type ( boost::bind ( &Foo::callback, this, _1, _2, _3 ) );
      if ( !ptrWorker ) {
         return - 1 ;
      }
      */
   }
   void testWorker() {
      /*
      ptrWorker->image() ;
      ptrWorker->metadata() ;
      ptrWorker->dlink() ;
      */
   }
};

int main() {
   Foo<DataLink> f;
   f.start() ;
   f.testWorker() ;
}

Open in new window


NB. I've noted you'll need to specialise some functions. I've not do so for you because it's not immediately obvious to me exactly what purpose they serve (and, indeed, whether you need all of them in Worker or whether each is specific to a different worker). If it's not clear what I mean and you'd like an additional example let me know -- but you'll probably need to provide me with a little more context.
0
 

Author Comment

by:forums_mp
ID: 38298803
Hi evilrix
Two things, I understand mccarls point but I think subclasses would result in the client being responsible for instantiating multiple classes.  Then again I suspect there could me a main worker class that allows clients to choose the appropriate class (image, Datalink, metadata) ..who knows.

Secondly lets assme for a discussion purposes I wanted all the specializations in Worker.  What would that look like?

There's alot of code, that serves as the lead up - if you will prior to invocation of the callback.

For instance.

  void Image ( ) {

    //lots of stuff ...
   //The img object got modified along the way..now tell the user about it
    handlerEnum = image_enum ;
    callBack ( dlink, meta, img ) ;
  }

Open in new window


There's one caveat.  Depending on the source data received all three member functions image, metadata and dlink member functions may get invoked.  So yes there's details missing that leads to invocation of all three members - again depending on the source data.

I think that's somewhat irrelevant though.  From a client perspective that's great however, the client just wants to be able to choose which source they should be notified about.   Not sure if that explanation helped.
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

Author Comment

by:forums_mp
ID: 38339245
evilrix you around?
0
 
LVL 40

Expert Comment

by:evilrix
ID: 38339707
Eeek. Oops... seems I overlooked responding to this. Sorry. I'll get onto this a little later (added it to my todo list) as I'm at work atm =/
0
 
LVL 40

Expert Comment

by:evilrix
ID: 38344778
>> Then again I suspect there could me a main worker class
The problem you have is differing function signatures. You would struggle to encapsulate that in an interface, hence my suggestion for a template aproach. If you are happy to have all the different functions defined in the interface then you could do this using the Abstract Factory Pattern.

http://en.wikipedia.org/wiki/Abstract_factory_pattern

From reading you last description I think I understand that you are looking to build a notification framework such that if an action happens (such as an image is modified) you want to user to be notified. Have you considered the Observer Pattern? I suspect that is what you are looking to implement.

http://en.wikipedia.org/wiki/Observer_pattern
0
 

Author Comment

by:forums_mp
ID: 38345281
Do me a favor. complete the example posted here:   evilrixPosted on 2012-08-13 at 16:06:27ID: 38290103, in particular the comments about 'specialization for different worker' types just so i get a concrete feel for what you're alluding to.  That solution might work

Thanks
0
 
LVL 40

Expert Comment

by:evilrix
ID: 38345302
Sure. I'll post something a little later for you.
0
 
LVL 40

Accepted Solution

by:
evilrix earned 600 total points
ID: 38347695
Ok, this is roughly what I had in mind. There is room for improvement and I may not have captured your problem domain exactly but I hope it gives you at least some idea how you could use meta-programming to solve your problem.

# include <iostream>

# include <boost/scoped_ptr.hpp>
# include <boost/shared_ptr.hpp>

# include <boost/function.hpp>
# include <boost/array.hpp>
# include <boost/asio.hpp>
# include <boost/thread.hpp>
# include <boost/thread/locks.hpp>
# include <boost/bind.hpp>
# include <boost/noncopyable.hpp>


class DataLink {};
class Metadata {};
class Image {};

typedef boost::function<void ( DataLink const&, Metadata const& , Image const& ) > LinkHandler;
typedef boost::function<void ( Metadata const& , Image const& ) > MetaHandler;
typedef boost::function<void ( Image const& ) > ImageHandler;

template <typename HandlerT>
class Worker_
{
      typedef HandlerT handler_type;
      handler_type  callBack ;

      DataLink dlink_;
      Metadata meta_ ;
      Image    img_ ;

   public :
      Worker_ ( const handler_type& handler )
         : callBack ( handler )
      {}

      void image ( );
      void metadata ( );
      void dlink ( );
};

// --- LinkHandler specialisations --->
template<>
void Worker_<LinkHandler>::image ( )
{
   callBack ( dlink_, meta_, img_ ) ;
}

template<>
void Worker_<LinkHandler>::metadata ( )
{
   callBack ( dlink_, meta_, img_ ) ;
}

template<>
void Worker_<LinkHandler>::dlink ( )
{
   callBack ( dlink_, meta_, img_ ) ;
}

// --- MetaHandler specialisations --->
template<>
void Worker_<MetaHandler>::image ( )
{
   callBack ( meta_, img_ ) ;
}

template<>
void Worker_<MetaHandler>::metadata ( )
{
   callBack ( meta_, img_ ) ;
}

template<>
void Worker_<MetaHandler>::dlink ( )
{
   callBack ( meta_, img_ ) ;
}

// --- ImageHandler specialisations --->
template<>
void Worker_<ImageHandler>::image ( )
{
   callBack ( img_ ) ;
}

template<>
void Worker_<ImageHandler>::metadata ( )
{
   callBack ( img_ ) ;
}

template<>
void Worker_<ImageHandler>::dlink ( )
{
   callBack ( img_ ) ;
}

typedef Worker_<LinkHandler> LinkWorker;
typedef Worker_<MetaHandler> MetaWorker;
typedef Worker_<ImageHandler> ImageWorker;

template <typename WorkerT>
class FooBase
{
   protected :
      typedef WorkerT worker_type;
      worker_type *ptrWorker ;

      FooBase ()
         : ptrWorker ( 0 )
      {}

      template <typename callbackT>
      bool start ( callbackT cb )
      {
         return (ptrWorker = new ( std::nothrow ) worker_type ( cb ));
      }

   public:
      void testWorker()
      {
         ptrWorker->image() ;
         ptrWorker->metadata() ;
         ptrWorker->dlink() ;
      }
};

template <typename WorkerT>
class Foo;

template <>
class Foo<DataLink> : public FooBase<LinkWorker>
{
   public :
      void callback ( DataLink const& d, Metadata const& m , Image const&  i )
      {

      }

      bool start ()
      {
         return FooBase<LinkWorker>::start ( boost::bind ( &Foo::callback, this, _1, _2, _3 ) );
      }
};


template <>
class Foo<Metadata> : public FooBase<MetaWorker>
{
   public :
      void callback ( Metadata const& m , Image const&  i )
      {

      }

      bool start ()
      {
         return FooBase<MetaWorker>::start ( boost::bind ( &Foo::callback, this, _1, _2 ) );
      }
};


template <>
class Foo<Image> : public FooBase<ImageWorker>
{
   public :
      void callback ( Image const&  i )
      {

      }

      bool start ()
      {
         return FooBase<ImageWorker>::start ( boost::bind ( &Foo::callback, this, _1 ) );
      }
};

int main()
{
   Foo<DataLink> f;
   f.start() ;
   f.testWorker() ;
}

Open in new window

0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.
Suggested Courses

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question