A design pattern for additional features?

I have a base class that inherits derived subclasses, it carries the basic functionality that should be the same for 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? I can only declare virtual functions and define them in derived classes that will 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 that would mean that if I change functions in any derived class, I will have to change the base class to reflect those changes.

Is there a design pattern specifically for this kind of problem? I've bought several books on design patterns, but I'm learning them on an "as needed" basis, so I have no idea if there is a pattern I'm looking for.

+1


a source to share


6 answers


You can find useful information about the chain of responsibility and rethink your decision that way.

Alternatively, you can declare "doRun" as a protected method and call it in the default base case.

default:
   doRun(input);

      



And define doRun in derived classes.

This is the so called template template template

+4


a source


I think you need a Chain of Responsibility pattern, or perhaps a Strategy combined with a dynamic call table ...



+4


a source


The usual way to deal with this is to use a factory. In the diagram:

  • create a hierarchy of related classes that provide functionality.
  • create a factory class that takes input and instantiates the appropriate class based on the input

Now for extra bonus points:

  • create a schema that regresses classes with a factory - you will need to specify the input and type of the class to handle it.

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

+1


a source


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

Why is this so?

I will remember your comment - then if you take this approach, you will have problems. Others have posted answers that suggest other solutions - I would check them to see if they help you.

+1


a source


If your selector values ​​are small integers, I would replace the case statement with a lookup table. (The actions in this case must be coded as a function, so you can put function pointers in a table). The inherited classes can then simply add records to the table. (I think the table should be an instance property, it cannot be static).

Colin

+1


a source


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 the Process () subclass. If you need to support more than two levels (for example a sub-subclass, adding even more cases), you need a dynamic mailing table.

+1


a source







All Articles