views:

173

answers:

6

I have a basic class that derived subclasses inherit from, it carries the basic functions that should be the same across all derived classes:

class Basic {
public:
    Run() {
     int input = something->getsomething();
     switch(input)
     {
      /* Basic functionality */
      case 1:
       doA();
       break;
      case 2:
       doB();
       break;
      case 5:
       Foo();
       break;
     }
    }
};

Now, based on the derived class, I want to 'add' more case statements to the switch. What are my options here? I can declare virtual functions and only define them in the derived classes that are going to use them:

class Basic {
protected:
    virtual void DoSomethingElse();
public:
    Run() {
     int input = something->getsomething();
     switch(input)
     {
      /* Basic functionality */
      ...

      case 6:
       DoSomethingElse();
     }
    }
};


class Derived : public Basic {
protected:
    void DoSomethingElse() { ... }
}

But this would mean when changing functions in any derived class, I would have to edit my base class to reflect those changes.

Is there a design pattern specifically for this kind of issue? I purchased a number of books on Design Patterns but I'm studying them on "by-need" basis, so I have no idea if there is such a pattern that I am looking for.

+1  A: 

The normal way of dealing with this is to use a factory. In outline:

  • create a hierarchy of related classes that provide the functionality.
  • create a factory class that takes the input and creates an instance of the right kindf of class depending on the input

Now for added bonus points:

  • create a scheme that reghisters classes withn the factory - you will need to specify the input and the type of the class to deal with it

Now when a need for a new input comes along, you just derive a new class and register it with the factory. The need for the switch statement disappears.

anon
I'll try to clarify my reasoning a little more: I don't need to derive based on the input: the derived classes wont live on the stack. I just want to seperate different types of logic but still keep some 'basic' logic for all derived classes.
Daniel
+4  A: 

I think the pattern you need is Chain Of Responsibility or maybe Strategy combined with a dynamic call table...

fortran
+1  A: 

But this would mean when changing functions in any derived class, I would have to edit my base class to reflect those changes.

Why would this be true?

I light of your comment - then if you choose this approach you'll have these issues. Others have posted answers that suggest other solutions - I'd check these out to see if they help you.

ChrisF
Well perhaps I worded it poorly. I don't have to do it when I change the contents of a function, but when I remove a function or change its name, I would have to go back to the Basic class to reflect those changes. Also, I don't want to end up with a 'Basic' class that has a ton of virtual functions; one for each function in any class that derives from it.
Daniel
that's only true if the Basic class needs to have the virtual functions... will any piece of code call such functions on the Basic class objects or are they just for private use within the subclasses?if the type of the classes is known for each object (that is, you aren't needing polymorphims, which seems to be the case) you don't need to declare the virtual functions in the base class.
fortran
+4  A: 

You may find useful to read about Chain of responsibility pattern and rethink your solution in that way.

Also you can declare 'doRun' as protected method and call it in the base default case.

default:
   doRun(input);

And define doRun in derived classes.

This is so called Template Method pattern

Mykola Golubyev
I think I will go for the Template Method pattern for now. I will definitely read up on and consider the other patterns listed here, but for now this can be marked as accepted :)
Daniel
+1  A: 

If your selector values are just small integers, I would replace the case statement by a lookup table. (The actions in the case will each need to be coded as a function, so you can put function pointers in the table). Then inherited classes can just add entries to the table. (I guess the table would have to be an instance property, it can't be static).

Colin

Colin Fine
I was thinking of using function pointers, but I'm relatively new to C++ and have not yet studied them deep enough to know how to use them with varying parameter usage.
Daniel
+1  A: 

А simple solution:

class Basic {
  public:
    void Run() {
      const int input = ...
      if (!(BaseProcess(input) || Process(input))) ...
    }

    vitual bool Process(int input) { return false; }

    bool BaseProcess(int input) {
      switch(input) {
    ...
        default: return false;
      }
      return true;
    }
...

...and then implement additional cases in subclass' Process(). If you need to support more than 2 levels (i.e. sub-subclass adding even more cases), then you'll need a dynamic dispatch table.

Igor Krivokon