A design question ....


F

forums_mp

#include <iostream>
#include <typeinfo>
#include <vector>

/// BEGIN "UNTOUCHABLE" CLASSES AND DATA
INSTANTIATORS ///////////////
class base {
public :
//handful of stuff
virtual ~base() {}
};

/*
one of many untouchable pn derived classes with
methods not found in base class
*/
class p1 : public base {
int value ;
public :
p1()
: value ( 0 )
{}
void set_something ( int in ) { value = in ; }
int get_something() const { return ( value ) ; }
~p1() {}
};

class p2 : public base {
public :
//stuff
~p2() {}
};
//up to pn
/// END "UNTOUCHABLE" Pn CLASSES AND DATA
INSTANTIATORS /////////////////


/*
============================================================
holder is a collection of UNTOUCHABLE classes, with useful
member data (For example) 'count'. For each call to Set_ a
phandler will
increment count
*/
typedef unsigned int unsigned_type ;
struct holder {
unsigned_type holder_id ;
unsigned_type count ;
static base *ptr ;
holder ( base *ptr_, unsigned_type const id )
: holder_id ( id )
{
ptr = ptr_;
}
virtual ~holder() { }
};
base* holder::ptr = 0 ;
typedef std::vector < holder* > holder_vec ;

/*
============================================================
base handler for d's.
notified upon receipt of a client message
*/
class d_handler_base {
public :
virtual void process() = 0 ;
virtual ~d_handler_base() {}
};
class d1_handler : public d_handler_base
{
holder_vec hv ;
//only interested in p1 objects located in the holder containers
p1* ptr_p1 ;

public :
d1_handler ( holder_vec& in )
: hv ( in )
//NOTE!!!!!!!!!!!!!!!!!
//ideally i need to use a map so i could interate and FIND p1
//for now we'll assume p1 exists at location 0 within holder_vec
, ptr_p1 ( static_cast < p1* > ( hv [ 0 ]->ptr ) )
{}
void process ()
{
unsigned_type const dummy = ptr_p1->get_something() ;
std::cout << std::hex << "0x" << dummy << std::endl;
}
};
class d2_handler : public d_handler_base
{
public :
d2_handler ()
{}
void process ()
{
std::cout <<"." << std::endl;
}
};

/*
============================================================
base handler for p's.
notified upon receipt of a server message
*/
class p_handler_base {
public :
virtual ~p_handler_base() {}
};
class p1_handler : public p_handler_base
{
holder_vec& hv;
p1* ptr_p1 ;

public :
p1_handler ( holder_vec& in )
: hv ( in )
, ptr_p1 ( static_cast < p1* > ( hv [ 0 ]->ptr ) )
{}
void update_p_msg ( unsigned_type const in ) {
ptr_p1->set_something ( in ) ;
hv [ 0 ]->count ++ ;
}
};


int main() {
static holder_vec hv ;
//this 'new new' stuff seems unsightly... i think a map would be
better....
// for now create a p1 with its id of 0x400, similarily a p2 with
it's id 0x500
hv.push_back ( new holder ( new p1(), 0x400 ) ) ;
hv.push_back ( new holder ( new p2(), 0x500 ) ) ;

d1_handler *ptrd1 = new d1_handler ( hv ) ;
p1_handler *ptrp1 = new p1_handler ( hv ) ;
//change
ptrp1->update_p_msg( 0xCAFE ) ;
ptrd1->process() ;

//change
ptrp1->update_p_msg( 0xDEAD ) ;
ptrd1->process() ;


std::cin.get() ;

}

In a nutshell:

Common message holder class (named holder) with a collection of base
classes. Within main a p1_handler object initiates a change to a p1
object (via the call to set_something). The d1_handler observes the
change.

At this juncture you may say this ‘screams’ an event handler (perhaps
observer implementation). This way any change to a Pn message by a Pn
handler is dispatched to a Dn handler.

My answer to an event handler (observer implementation) is No!
Here’s why: Referencing the d1 and d2 handler classes within source
above:

a) Not all Dn handlers is interested in Pn (UNTOUCHABLE) messages.
For instance, the message holder vec holding Pn messages is a
_dont_care_ for a d2_handler.

b) For those Dn handler interested in Pn messages (i.e d1_handler),
these Dn handlers are not interested in being notified of immediate
changes to Pn messages by Pn handlers. These Dn handlers is only
interested in knowing they have the ‘latest’ Pn message _whenever_
(600 updates could have occurred since) they access a Pn message
object.

From a development perspective, here's where I'm struggling with in
this case C++. The design and what (perhaps) pattern to use to
achieve the objective. After scanning the GOF here are my thoughts:

1) Leave well enough alone. Current implementation works but then I’m
often not satisfied given my struggles
2) Add a proxy class between the Pn handlers and Dn handlers. I
suspect this would be beneficial to the Dn handlers (more so that Pn
handler since a Pn message could be local to a Pn handler). In doing
so the Dn handler could request via the Proxy for a Pn message and
receive the ‘lastest/most up to date’ Pn message. The drawback here is
the overhead and (worse) I’m not sure how to implement a proxy (at
least not yet)
3) Perhaps a common base class between Pn handlers and Dn handlers
would suffice.

My question is - is there a better way to do this? Thoughts/ideas
welcomed.

Thanks in advance
 
Ad

Advertisements

N

ng2010

Whoa! That's a lot of code and verbage to be a "design" question! Is
there really no higher-level way to express your "design" issue?

#include <iostream>
#include <typeinfo>
#include <vector>

/// BEGIN "UNTOUCHABLE" CLASSES AND DATA
INSTANTIATORS ///////////////
class base {
public :
//handful of stuff
virtual ~base() {}
};

/*
one of many untouchable pn derived classes with
methods not found in base class
*/
class p1 : public base {
int value ;
public :
p1()
: value ( 0 )
{}
void set_something ( int in ) { value = in ; }
int get_something() const { return ( value ) ; }
~p1() {}
};

class p2 : public base {
public :
//stuff
~p2() {}
};
//up to pn
/// END "UNTOUCHABLE" Pn CLASSES AND DATA
INSTANTIATORS /////////////////


/*
============================================================
holder is a collection of UNTOUCHABLE classes, with useful
member data (For example) 'count'. For each call to Set_ a
phandler will
increment count
*/
typedef unsigned int unsigned_type ;
struct holder {
unsigned_type holder_id ;
unsigned_type count ;
static base *ptr ;
holder ( base *ptr_, unsigned_type const id )
: holder_id ( id )
{
ptr = ptr_;
}
virtual ~holder() { }
};
base* holder::ptr = 0 ;
typedef std::vector < holder* > holder_vec ;

/*
============================================================
base handler for d's.
notified upon receipt of a client message
*/
class d_handler_base {
public :
virtual void process() = 0 ;
virtual ~d_handler_base() {}
};
class d1_handler : public d_handler_base
{
holder_vec hv ;
//only interested in p1 objects located in the holder containers
p1* ptr_p1 ;

public :
d1_handler ( holder_vec& in )
: hv ( in )
//NOTE!!!!!!!!!!!!!!!!!
//ideally i need to use a map so i could interate and FIND p1
//for now we'll assume p1 exists at location 0 within holder_vec
, ptr_p1 ( static_cast < p1* > ( hv [ 0 ]->ptr ) )
{}
void process ()
{
unsigned_type const dummy = ptr_p1->get_something() ;
std::cout << std::hex << "0x" << dummy << std::endl;
}
};
class d2_handler : public d_handler_base
{
public :
d2_handler ()
{}
void process ()
{
std::cout <<"." << std::endl;
}
};

/*
============================================================
base handler for p's.
notified upon receipt of a server message
*/
class p_handler_base {
public :
virtual ~p_handler_base() {}
};
class p1_handler : public p_handler_base
{
holder_vec& hv;
p1* ptr_p1 ;

public :
p1_handler ( holder_vec& in )
: hv ( in )
, ptr_p1 ( static_cast < p1* > ( hv [ 0 ]->ptr ) )
{}
void update_p_msg ( unsigned_type const in ) {
ptr_p1->set_something ( in ) ;
hv [ 0 ]->count ++ ;
}
};


int main() {
static holder_vec hv ;
//this 'new new' stuff seems unsightly... i think a map would be
better....
// for now create a p1 with its id of 0x400, similarily a p2 with
it's id 0x500
hv.push_back ( new holder ( new p1(), 0x400 ) ) ;
hv.push_back ( new holder ( new p2(), 0x500 ) ) ;

d1_handler *ptrd1 = new d1_handler ( hv ) ;
p1_handler *ptrp1 = new p1_handler ( hv ) ;
//change
ptrp1->update_p_msg( 0xCAFE ) ;
ptrd1->process() ;

//change
ptrp1->update_p_msg( 0xDEAD ) ;
ptrd1->process() ;


std::cin.get() ;

}

In a nutshell:

Common message holder class (named holder) with a collection of base
classes. Within main a p1_handler object initiates a change to a p1
object (via the call to set_something). The d1_handler observes the
change.

At this juncture you may say this 'screams' an event handler (perhaps
observer implementation). This way any change to a Pn message by a Pn
handler is dispatched to a Dn handler.

My answer to an event handler (observer implementation) is No!
Here's why: Referencing the d1 and d2 handler classes within source
above:

a) Not all Dn handlers is interested in Pn (UNTOUCHABLE) messages.
For instance, the message holder vec holding Pn messages is a
_dont_care_ for a d2_handler.

b) For those Dn handler interested in Pn messages (i.e d1_handler),
these Dn handlers are not interested in being notified of immediate
changes to Pn messages by Pn handlers. These Dn handlers is only
interested in knowing they have the 'latest' Pn message _whenever_
(600 updates could have occurred since) they access a Pn message
object.

From a development perspective, here's where I'm struggling with in
this case C++. The design and what (perhaps) pattern to use to
achieve the objective. After scanning the GOF here are my thoughts:

1) Leave well enough alone. Current implementation works but then I'm
often not satisfied given my struggles
2) Add a proxy class between the Pn handlers and Dn handlers. I
suspect this would be beneficial to the Dn handlers (more so that Pn
handler since a Pn message could be local to a Pn handler). In doing
so the Dn handler could request via the Proxy for a Pn message and
receive the 'lastest/most up to date' Pn message. The drawback here is
the overhead and (worse) I'm not sure how to implement a proxy (at
least not yet)
3) Perhaps a common base class between Pn handlers and Dn handlers
would suffice.

My question is - is there a better way to do this? Thoughts/ideas
welcomed.

Thanks in advance
 

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

Top