Sign in to follow this  

C++ class design issue

This topic is 2545 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm writing the part of a webserver that handles requests (e.g. reads the requested file or makes a nice list of all the items in a directory).

class handler
{
public:
handler(void);
virtual ~handler(void);

virtual void handle_async(const request &request, reply &reply, filesystem::item &item);
};


"filesystem::item &item" is a reference to the abstract base class of the filesystem: files, folders and other items are derived from it.

A design choice was that the file system and the request handler are two separate entities: we want client code to be able to add new functionality to the request handler without having to modify the file system and vica versa. Because we want to be able to mix functionality or maybe change behaviour of the webserver on the fly we create a delegate class that will handle requests of a certain type.

class delegate
{
public:
explicit delegate(void)
virtual ~delegate(void);

virtual void operator () (const request &request, reply &reply, filesystem::item &item) = 0;
};


Now for the problem I ran into: all that our handler class has to do is find the correct delegate for each "filesystem::item &item" that is passed in. My idea was to use the typeid of the filesystem::item as an index to a map that contains the delegates because 've read that typeid will give us the type of the actual derived class from a base reference.

class handler
{
public:
handler(void);
virtual ~handler(void);

virtual void handle_async(const request &request, reply &reply, filesystem::item &item)
{
auto iterator = delegates.find(typeid(item));
if(iterator != delegates.end()){
*iterator(request, reply, item);
}else{
// Problem!
}
}

protected:
std::map<const std::type_info, delegate *> delegates_;
};


However, there is one main issue with this: if there is no delegate for that specific item, we can't easily test if there is a delegate for a certain base class (somewhere in the entire class hierarchy) of the item. What would be the best way to find a base class? Or is there a better solution for this problem?

Share this post


Link to post
Share on other sites
To implement a chain-of-responsibility pattern I will have to build a tree of all delegates.


I will have to give each delegate a function to see if it can handle a certain item:

class delegate 
{
virtual void operator () (const request &request, reply &reply, filesystem::item *item) = 0;
/*...*/
virtual bool test(filesystem::item *item) const = 0;
/*...*/
};

class folder_delegate // example
: public delegate
{
virtual void operator () (const request &request, reply &reply, filesystem::item *item)
{
filesystem::folder *folder_ = dynamic_cast<filesystem::folder *>(item);
if(folder_ == 0){
throw "Can't handle request"
}else{
// handle the request
}
}


virtual bool test(filesystem::item *item) const
{
return dynamic_cast<filesystem::folder *>(item) != 0;
}
}




Apart from the trouble of creating the tree and maybe checking for duplicate delegates, im worried about the performance. Traversing the tree requires a dynamic_cast for each node and then another one when we've finally found our delegate. Is there a better way to implement this? Or can I get more information about the inheritance hierarchy of an object during runtime (more than typeid gives us)?

Share this post


Link to post
Share on other sites
I think you've severely overcomplicated this.


Here's how I would approach writing a web server with similar capabilities:

  • Define a request to be a generic, unparsed URL

  • Create a dispatcher that accepts a request and parses it for file/directory names, querystring parameters, etc.

  • Hand off the parsed request data to a chain of responsibility composed of resources. Each resource examines the given file/directory name, querystring, etc. and decides if it can handle the request. If so, it returns a response directly. If not, it delegates to the next link in the chain.

  • The last link in the chain is defined to always be an error fallback mechanism


That should easily solve your design requirements, keep things nice and loosely coupled, and eliminate all these extra layers of delegate and handler cruft. Outside the chain of responsibility itself, you don't even need virtual dispatch, let alone dynamic_casts [smile]

Share this post


Link to post
Share on other sites

This topic is 2545 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this