-1

Following is the pseudo code to describe the problem:

class Client
{
public:
    void F1(A*);    //import
    void F2(A*);    //export
    void F3(A*);    //print
    void ...
    void F100(A*);  //validate
};

Client::F3(A* p)
{
    p->F3();
}

class A
{
public:
    int memberA;
    virtual void F3();
};

class B : public A
{
public:
    int memberB;
    virtual void F3();
};

class C : public B
{
public:
    int memberC;
    virtual void F3();
};

void A:F3()
{
    print(memberA);
}

void B:F3()
{
    A:F3();
    print(memberB);
}

void C:F3()
{
    B:F3();
    print(memberC);
}

The client is using class A and possibly its derivatives, and it has 100 ways of using it. E.g. import/export/print/validate etc.

Keep in mind that the sub class will call the base class plus something of its own.

I know a way to implement this is to let class A/B/C all implement these 100 functions. For example: F3, the print functionality and their implementations.

The problem is that if I implement all these 100 functions in all classes in the inheritance chain (these A/B/C is just a simplified model, in real world, there could be more than 10 layers of inheritance), each single class will become too fat.

Could you help me to refactor it?

milesma
  • 1,561
  • 1
  • 15
  • 37
  • Make interfaces for smaller sets of functionality. – πάντα ῥεῖ Jul 01 '14 at 07:10
  • Do you really need inheritance, or just using it for implementation? I mean, are conceptually C a "kind of" B, and B a kind of A and so on? – Gonmator Jul 01 '14 at 07:14
  • @πάνταῥεῖ in my example, even an interface has only one function F3(), I still have to implement it in class A/B/C, if there are 100 functions relying on the inheritance, the classes are still fat. – milesma Jul 01 '14 at 12:49
  • @Gonmator yes. This is a simplified piece of code to for describing the issue. – milesma Jul 01 '14 at 12:51

1 Answers1

0

Maybe you could use the Visitor Pattern. Each of your functions represents a Visitor, A and its derivatives only have a single accept function:

struct Visitor {
  void visit(A&);
  void visit(B&);
  void visit(C&);
};

struct F1 : Visitor {
  void visit(A&);
  void visit(B&);
  void visit(C&);
};
// ...
struct F100 : Visitor {
  void visit(A&);
  void visit(B&);
  void visit(C&);
};


class A {
public:
  virtual void accept(Visitor& v) {v.visit(*this);}
}

class B : public A {
public:
  virtual void accept(Visitor& v) {v.visit(*this);}
}

This may or may not be interesting, depending on possible extensions you have to make and how you want to encapsulate functionality. Basically, this makes it easier to implement new functions F101...F200 and centers a function code in a single class, but if you have to implement new classes D...Z, you have to adapt each single function, which is already implemented.

Community
  • 1
  • 1
MatthiasB
  • 1,759
  • 8
  • 18
  • Thanks, but where is the benefit of inheritance in your example? – milesma Jul 01 '14 at 12:59
  • Inheritance of Fx -> Visitor or inheritance of B -> A? The overall goal is to be able to call `accept()` on any subclass of A and still call the appropriate `F100::visit(&)` function for the subclass. – MatthiasB Jul 02 '14 at 06:51
  • Yes. I know you used inheritance by a base pointer of A and call sub class by polymorphism. Oh! did you mean F3::visit(C&) can reuse F3::visit(B&) plus its own extra code? – milesma Jul 02 '14 at 07:22
  • I did not think about it, but this should be the case anyways. The main advantage is that you centralise your implementation of F1...F100 in a single file and not spread it over all your classes. – MatthiasB Jul 02 '14 at 07:25
  • I will give a try on this tomorrow: F3::visit(A&){print(A.memberA);} F3::visit(B&){visit((A)B); print(B.memberB);} F3::visit(C&){visit((B)C); print(C.memberC);} then let you know the status. Thank you very much. – milesma Jul 02 '14 at 07:26
  • I think we are on the right track. then the Vistor classes can implement some interfaces or base classes. I will give a try tomorrow. – milesma Jul 02 '14 at 07:29