3

Let me introduce the following three classes: AbstractProcessor and these two child classes. The code below is not complex because there are only two child classes, but what if procedures1 and procedure2 both has many N candidate implementation? In such case, there are NxN child classes and a lot of duplication will be made by hand-coding. In the code below for example, each procedure can either be fast one or accurate one. So there are 2x2 possible child classes.

I would ask about technique/design pattern to reduce duplication. More precisely, is there any technique to reduce that NxN hand-coding to 2N hand-coding?

Noting that procedure1 and procedure2 both have to share the same var_ (in my case it is measurement value of physical world of robot) and the common function foo(), procedure1 and procudure2 can hardly be composed by a has-a relationship. Actually in my application, there are lot of var_ because the robot access to many type of sensors.

class AbstractProcessor
{
  virtual void procedure1() = 0;
  virtual void procedure2() = 0;

  Something foo(){ // ... 
  }
  double var_;

  void run(){
    procedure1();
    procedure2();
  }
};

class FastProcessor : public AbstractProcessor
{
  void procedure1() override {// ... fast procedure ( use foo and var_ inside)
  }
  void procedure2() override {// ... fast procedure ( use foo and var_ inside)
  }
};

class AccurateProcessor : public AbstractProcessor
{
  void procedure1() override {// ... accurate procedure ( use foo and var_ inside)
  }
  void procedure2() override {// ... accurate procedure ( use foo and var_ inside)
  }
};
orematasaburo
  • 1,207
  • 10
  • 20
  • It reminds me of the Strategy pattern... – K.R.Park Feb 09 '22 at 07:46
  • 1
    You might provide an implementation of `AbstractProcessor` which can be configured with functor classes, or lambda functions for the several procedures, instead of using plain inheritance. – πάντα ῥεῖ Feb 09 '22 at 07:46
  • "procedure1 and procudure2 can hardly be composed by a has-a relationship." can you clarify? Why not? Is this a false premise, or is there something that prevents you from storing `procedure1` and `procedure2` as members? – 463035818_is_not_an_ai Feb 09 '22 at 08:00
  • If you have `procedure1`, `procedure2`, ..., `procedureN` each of which can have both fast and accurate implementations, and you want to be able to configure any combination of them *at run time*, then it is clear that each of the 2N implementations must be a separate entity (an object or a standalone function). – n. m. could be an AI Feb 09 '22 at 08:03

1 Answers1

3

Inheritance is not the solution to everything. Sometimes all the problems are gone once you don't use inheritance. There are many different ways to do what you want. One is to store the callables as members:

#include <functional>
#include <iostream>

struct Processor
{
  std::function<void(Processor*)> procedure1;
  std::function<void(Processor*)> procedure2;

  double var_ = 42.0;
  void foo() {
      std::cout << "hello foo\n";
  }

  void run(){
    procedure1(this);
    procedure2(this);
  }
};

int main() {
    Processor proc{
        [](auto p) { std::cout << p->var_ << "\n";},
        [](auto p) { p->foo(); }
    };
    proc.run();
}

Instead of lambdas the parameters to the constructor could be free functions so they can be more easily be reused. Note that I hade to make everything public in the class, in your example everything is private (it cannot work like that).

As you are asking for a technique/design pattern, the term "composition over inheritance" fits best here I think. Dependency injection and other related design patterns might also help you to get into a different way of thinking about your design.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185