3

I am designing a C++ module. This module can receive 3 different types of requests: Request-A, Request-B and Request-C.
For each type, I have a corresponding handler class: RequestHandler-A, RequestHandler-B and RequestHandler-C (all of these implement the IRequestHandler interface).
Each handler has to carry out certain actions to fulfill its request.
For example, RequestHandler-A needs to perform these in sequence:
Action-1
Action-2
Action-3
Action-4
Action-5

RequestHandler-B needs to perform these in sequence:
Action-1
Action-3
Action-5

RequestHandler-C needs to perform these in sequence:
Action-4
Action-5

The result of one action is used by the next one.

I am struggling to design these classes so that common action implementations are reused across handlers. Are there any design patterns that can be applied here? Maybe Template method pattern could be a possibility but I am not sure. Any suggestions would be greatly appreciated.

PS: to make things more interesting, there is also a requirement where, if Action-2 fails, we should retry it with different data. But maybe I am thinking too far ahead.

4

4 回答 4

4

"Common implementations" means that your solution does not have anything to do with inheritance. Inheritance is for interface reuse, not implementation reuse.

You find that you have common code, just use shared functions:

void action1();
void action2();
void action3();
void action4();
void action5();

struct RequestHandlerA : IRequestHandler {
    virtual void handle( Request *r ) {
        action1();
        action2();
        action3();
    }
};

struct RequestHandlerB : IRequestHandler {
    virtual void handle( Request *r ) {
        action2();
        action3();
        action4();
    }
};

struct RequestHandlerC : IRequestHandler {
    virtual void handle( Request *r ) {
        action3();
        action4();
        action5();
    }
};

Assuming that the common function are just internal helpers, you probably want to make them static (or use an anonymous namespace) to get internal linkage.

于 2013-07-12T15:16:20.890 回答
2

Are you looking for something like this?

#include <iostream>

using namespace std;

class Interface{
    public:
        void exec(){
            //prepare things up
            vExec();
            //check everything is ok
        };
        virtual ~Interface(){}
    protected:
        virtual void vExec() = 0;
        virtual void Action0() = 0;
        virtual void Action1(){}
        void Action2(){}
};

void Interface::Action0(){
}

void Action3(){}

class HandlerA : public Interface{
    protected:
        virtual void vExec(){
            Action0();
            Action1();
            Action3();
        }
        virtual void Action0(){
        }
};

class HandlerB : public Interface{
    protected:
        virtual void vExec(){
            Action0();
            Action1();
            Action2();
            Action3();
        }
        virtual void Action0(){
            Interface::Action0();
        }
};

int main()
{
    Interface* handler = new HandlerA();
    handler->exec();
    HandlerB b;
    b.exec();

    delete handler;
}

As you can see the actions can be virtual members, non-virtual members, free functions, or whatever you might think of, depending on what you need.

The "additional" feature of feeding the actions with different data can be performed in exec() (if it is generic) or in vExec (if it is handler specific). If you give us more details I can modify the example accordingly.

Also, you can make vExec public and get rid of exec. The one in the example is just a practice I like most (making interface non-virtual and virtual functions non-public).

于 2013-07-12T14:51:55.957 回答
1

You can have one base class which implements the 5 actions and have the handlers derive from it.

If the actions are sufficiently isolated from each other, you can probably separate them out into individual functions or classes too and just have the handler call those.

于 2013-07-12T14:45:54.377 回答
0

Have you considered the Chain Of Command design pattern? http://en.wikipedia.org/wiki/Command_pattern

It is a time proven pattern that promotes loose coupling among handler objects and the requests(commands) they receive.

What you could do is translate the request objects to act as Command Objects. You then specify which type of Commands each of your Handler's can undertake. You can then pass the command to the Handlers and have them pass the command forward if they cannot handle them. If a handler can handle the action, then the command is processed through each of its respective Actions. You can then have each logical action reside within the Handler as objects themselves, utilizing composition.

于 2013-07-12T14:53:37.383 回答