Eine andere, etwas allgemeinere Methode leitet sich vom Grundsatz ab:
Wenn du ein Problem nicht dingfest machen kannst, dann mach eine Klasse
draus.
Das funktioniert so:
Anstatt eines Funktionspointers kriegt die Instanz ein Objekt übergeben,
welches darüber bescheid weiß, welche andere Methode in welchem anderen
Objekt aufzurufen ist. Der Auslöser der Funktionalität bemüht nicht den
Funktionspointer um eine Methode in einem anderen Objekt aufzurufen,
sondern er wendet sich an einen Proxy.
Dazu machen wir einfach mal eine Basisklasse, von der dann später die
einzelnen konkreten Proxies abgeleitet werden:
1 | class Proxy
|
2 | {
|
3 | public:
|
4 | virtual ~Proxy() {}
|
5 | void CallIt( char Daten ) = 0;
|
6 | };
|
So weit so gut.
Dein MyClass Objekt hält jetzt so einen Proxy und da das ganze Polymorph
verwendet werden soll, hält es genau genommen einen Pointer (einen
non-owning Pointer, soll heißen: Ein MyClass Objekt ist nicht für die
Verwaltung new/delete der Proxies zuständig)
1 | class MyClass
|
2 | {
|
3 | public:
|
4 | MyClass() : pProxy( NULL ) {};
|
5 |
|
6 | void SetProxy( Proxy* pProxy ) { pProxy_ = pProxy; }
|
7 | void Receive( char Daten );
|
8 |
|
9 | private:
|
10 | Proxy* pProxy_;
|
11 | }
|
Wird, wie gehabt, Receive aufgerufen, so leitet Receive diesen Aufruf
weiter. Natürlich nur, wenn es überhaupt einen Proxy gibt:
1 | void MyClass::Receive( char Daten )
|
2 | {
|
3 | ....
|
4 |
|
5 | if( pProxy )
|
6 | pProxy->CallIt( Daten );
|
7 | }
|
Alles was noch fehlt, ist der konkrete Proxy, der einen CallIt Aufruf an
ein MyClass Object weitergeben kann, indem er dessen Receive Funktion
aufruft. Der ist aber schnell gemacht. Auch er bekommt wieder einen
Pointer auf das Objekt, dessen Receive Methode zuständig ist (und der
Non-Owning ist)
1 | class MyClassProxy : public Proxy
|
2 | {
|
3 | public:
|
4 | MyClassProxy( MyClass* pReceiver ) : pReceiver_( pReceiver ) {}
|
5 | void CallIt( char Daten ) { pRecevier->Receive( Daten ); }
|
6 | }
|
Damit sind alle Zutaten zusammen und main kann geschrieben werden:
1 | int main()
|
2 | {
|
3 | MyClass MyObject1, MyObject2;
|
4 |
|
5 | MyClassProxy MyProxy( &MyObject2 ); // Der Proxy soll an MyObject2 weitergeben
|
6 | MyObject1.SetProxy( &MyProxy ); // Und MyObject1 soll den Call über
|
7 | // den Proxy MyProxy weitergeben
|
8 |
|
9 | MyObject1.Receive( 'A' ); // MyObject1 benachrichtigt jetzt
|
10 | // mithilfe des Proxies das Obj MyObject2
|
11 | // das Daten eingetroffen sind.
|
12 | }
|
Der Vorteil eines Proxies besteht darin, dass MyClass jetzt nicht mehr
daran gebunden ist, den exakten Typ des aufzurufenden Objektes zu
kennen. Diese Information steckt im Proxy selber und der kann an die
jeweilige Situation angepasst werden. Haargenau das gleiche MyClass
Objekt kann mit einem anderen Proxy dazu gebracht werden, eine Methode
in einem MyOtherClass Object aufzurufen. Dazu braucht es lediglich einen
dafür massgeschneiderten Proxy.
Der Nachteil ist natürlich, dass die Aufrufe über den Proxy ein wenig
langsamer sind, weil ja eine Abstraktionsschicht zwischengeschoben
wurde. Aber so dramatisch sind die Speed-Unterschiede dann auch wieder
nicht.