Refactoring tightly related classes when only one side can be changed
Please accept my apologies in advance for the somewhat lengthy question. This is the smallest stand-alone example I could come up with ... I'm sure there must be some obvious / nice / neat solution to solve this problem, but I don't see it at the moment.
Ok, here's the problem: imagine the following situation (nb. Compiled version of the code is available at http://goo.gl/dhRNex ). Let be
struct Thing1 {
public:
void bar(class Implementation1 &i) {
i.baz();
}
// ...various other methods like bar()
};
struct Thing2 {
public:
void bar(class Implementation2 &i) {
i.qux();
}
// ...various other methods like bar()
};
... Unfortunately, these classes are fixed, i.e. Cannot be changed / reorganized.
However, they are Implementation1
also Implementation2
changeable. These two classes have a lot of the same code, so it is natural to use common code in a common base class. However, the code depends on the type used Thing
, but there is no common base class for Thing1
and Thing2
, so it seems natural to use templates. So I worked out the following base class solution
template<class T, class S>
struct ImplementationBase {
public:
S *self;
void foo() {
T thing;
thing.bar(*self);
}
// ...lots more shared code like foo()
};
and specific implementations
struct Implementation1 : public ImplementationBase<class Thing1, class Implementation1> {
public:
Implementation1() {
self = this;
}
void baz() {
std::cout << "Qux!" << std::endl;
}
};
struct Implementation2 : public ImplementationBase<class Thing2, class Implementation2> {
public:
Implementation2() {
self = this;
}
void qux() {
std::cout << "Qux!" << std::endl;
}
};
Ideally, instead of self
in foo
should be used this
, but the problem is that it this
has a type ImplementationBase<class Thing1, class Implementation1>
but is required Implementation1
. Obviously, all this is quite a mess, and the classes Implementation
and Thing
too closely related, but I do not see an easy way out, not being able to reorganize classes Thing
. So finally my questions:
- Is there a better alternative to using the trick
self
above? - Is there a design that better resolves this problem? (I have a feeling, I have, but that I will miss something obvious)
If you've made it this far, thank you so much for taking the time to read the whole story and my apologies again for this long-standing question.
source to share