0

I have the same problem as this I have some problems about this project?, but due to the title was poorly written, the topic has been closed.
Basically, I have n classes, derived from a base class. Build a new class with its behaviors and attributes are based on matched combination (predefined) of those derived classes.
In his code he used a lot of if cases to find out the combination, which is cumbersome and the expandability is almost impossible. Can a design pattern replace those if cases?
E.g:

A+B+A = B+A+A = ... = A+B (combination 1)
A+A+A = no combination  

Pseudocode:

class base

class A : public base
class B : public base
class C : public base

class combine : public base{
  void combine(base&, base&, base&){
    if(isA && isB && isC)
        //implement combination1 here
    else((isA && isB)) || (isB && isA))
        //implement combination2 here
    else(...)//and a lot more
  }  
};

Update #1:

Why combine class is derived from base? As example in the link, combine is still just a Robot (base), with superior stat.
Found out that Decorator is pretty suitable for this problem, however, still need if cases to determine which Decorator to use (at least it's now outside the class)

Pseudocode:

class decorator : public base{
protected:
    base* m_base;
public:
    m_base& setStat(base&);//set stat for m_base
}
class A_and_B : public decorator
class A_and_C : public decorator
//more combination

base* combine(base&, base&, base&){
    combine megatron;
    if((isA && isC)) || (isC && isA)){
        A_and_C decor;
        return decor.setStat(megatron);
    }
    else((isA && isB)) || (isB && isA))
        A_and_B decor;
        return decor.setStat(megatron);
    }
    else(...)//and a lot more
}
Phineas
  • 159
  • 2
  • 10
  • you want to make one class inheriting from all the classes? – foragerDev Sep 18 '20 at 10:09
  • Consider using multiple-inheritance instead. But actually it depends on your needs to manipulate the object properties, so you need to describe why you don't like the if/else version. – Hack06 Sep 18 '20 at 10:12
  • no, only the behaviors are based on combination of classes, it's like mixing potion, A + A + A gives you nothing, but A + B (B + A is the same) or B + C does. – Phineas Sep 18 '20 at 10:13
  • 1
    if/else I think it's not elegant, not expandable. While multi inheritance can have diamond problem, or in Java, have no multi inheritance at all – Phineas Sep 18 '20 at 10:16
  • 4
    It is not exactly clear what you want to combine and at what point of time (compile-time/runtime). Also, the linked question is not fully clear about that. Is it just about the values of the members that change based on the combination, or also about combining/altering member functions? If it is just about the values of the members, then this sounds more like using template specialization of free functions and/or factory functions instead of inheritance. At runtime, you don't have much of a choice than having a map or a if-clauses. – t.niese Sep 18 '20 at 10:28
  • 4
    @Phineas, the problem solving starts with problem definition. So you should first clarify in which language you're coding, what are you trying to reach, and what's the main problem in that path. Regarding to diamond problem, there are solutions for that too. In Java (starting from version 8) you can do multiple inheritance with Interfaces. Regarding to elegance/expansion, it's a debatable question, but what are you trying to extend/parametrize, the number of extensions, properties, or something else? – Hack06 Sep 18 '20 at 10:30
  • I think that if you are asking such questions, you are already overthinking your design. This might be a X-Y problem. What are your trying to achieve? – JHBonarius Sep 18 '20 at 10:55
  • I think I kind of get what you want, but I'm a bit confused by your example. Why is `combine` a class, and why does it inherit from `base`? Are you looking for a way to automate something like `struct Thing : A, C { void doStuff() { /* something deduced from the A + C combination */ } }`? – Quentin Sep 18 '20 at 11:04

2 Answers2

0

I think you are looking for Double Dispatch pattern, but you may need a metoprogramming technique based on Variadic Templates or combination of them.

See also Understanding double dispatch C++ and Multiple dispatch in C++

The most natural solution is overloading of operator + . Something like this

class Combi;

class base
{
  public:
    virtual Combi Plus(base& x) = 0;
    virtual Combi Plus(A& a) = 0;
    virtual Combi Plus(B& b) = 0;
    virtual Combi Plus(Combi& x);
};

Combi CombiAA(A&, A&);
Combi CombiAB(A&, B&);

class A : public base
{
  public:
    virtual Combi Plus(base& x)
    {
       return x.Plus(*this);
    }
    
    virtual Combi Plus(A& a)
    {
       return CombiAA(a, *this);
    }

    virtual Combi Plus(B& b)
    {
       return CombiAB(b, *this);
    }

    virtual Combi Plus(Combi& x)
    {
       return x.Plus(*this);
    }
};

//
//
class AB : public base
{
  //... implement combination A&B here
};


class Combi : public base
{
  public:
    Combi(std::shared_ptr<base> obj) : m_obj(obj) {}; 
    virtual Combi Plus(base& x)
    {
       return x.Plus(*m_obj);
    }
    
    virtual Combi Plus(A& a)
    {
       return a.Plus(*m_obj);
    }

    virtual Combi Plus(B& b)
    {
       return b.Plus(*m_obj);
    }

    virtual Combi Plus(Combi& x)
    {
       return x.Plus(*m_obj);
    }
  private:
    std::shared_ptr<base> m_obj;
};


// it have to implement all of the functions, that creates the object combination:
Combi CombiAA(A&, A&);
Combi CombiAB(A&, B&);
Combi CombiBB(B&, B&);

Combi CombiAA(A& a1, A& a2)
{
  return Combi(std::make_shared<A>(a1));
}


Combi CombiAB(A& a, B& b)
{
  return Combi(std::make_shared<AB>(a, b));
}


Combi operator + (Base& lhs, Base& rhs)
{
  return lhs.plus(rhs);
}


A a;
B b;

auto x = a+b;
B0FEE664
  • 191
  • 5
0

Why combine class is derived from base?

As example in the link, combine is still just a Robot (base), with superior stat.

If you play only with stat, inheritance is maybe not the good approach from start.

Additionally, what happen when you combine a robot already generated from combine?

(isA && isB) || (isB && isA)

if IsA/isB are boolean, (isA && isB) would be suffisent.

if you meant if robotX is a A and robotY is a B then, as order seems not important, you might have

const bool isA = dynamic_cast<A*>(robot1) != nullptr || dynamic_cast<A*>(robot2) != nullptr || dynamic_cast<A*>(robot3) != nullptr;

to be informer case.

Basically, I have n classes, derived from a base class. Build a new class with its behaviors and attributes are based on matched combination (predefined) of those derived classes. In his code he used a lot of if cases to find out the combination, which is cumbersome and the expendability is almost impossible. Can a design pattern replace those if cases?

You can turn the if chain by switch case or a std::mapby transforming your different if into a flag number, something like:

unsigned int flag = (isA << 0) | (isB << 1) | (isC << 2);

switch (flag)
{
case 3: /*1 << 0 | 1 << 1*/ /* A|B */ return combination1;
case 7: /*1 << 0 | 1 << 1*/ /* A|B */ return megatron;
// ...
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302