Du bist nicht angemeldet.

1

Freitag, 16. März 2012, 16:59

Interfaces in Objective-C und das Decorator-Pattern

Hallo,


ich möchte für verschiedene Dateioperationen (Copy, Move, ...) separate Klassen anlegen. All diese Operationen sollen die Methode "-(void) run" implementieren.
Jetzt möchte ich EINEN Decorator für alle Operationen schreiben welcher beispielsweise einen Log-Eintrag beim Aufruf von "run" erzeugt, egal um welche konkrete Operation es sich handelt und den Aufruf von "run" an eine spezielle Operation weiterreicht.

Ich komme von PHP und dort würde ich das Ganze mit einem Interface "Operation" lösen welches zum Einen von den konkreten Klassen Move, Copy, ... und zum Anderen von meinem Dekorator OperationLog implementiert wird. Dann würde ich jede neue Operation in ein Objekt von OperationLog im Konstruktor übergeben. Jeder run()-Aufruf wird dann geloggt und entsprechend an die spezielle Operation weitergereicht.

Gibt es in Objective-C eine elegante Methode das Decorator-Pattern umzusetzen? Oder gibt es einen anderen Weg das sauber zu lösen?
Wichtig ist mir dass die verschiedenen Operationen nicht mit dem Logging überladen werden. Das Logging soll nur ein Beispiel sein - im Prinzip geht es mir später um Erweiterung der Funktionalität der Operationen, welche für alle Operationen dieselbe sein wird, z.B. auch das Versenden von einem Event 'Operation started'.

2

Freitag, 16. März 2012, 20:29

Hallo,

ich habe keine Ahnung von PHP und verstehe auch nur die Hälfte.

Aber ich lese einfach raus, dass Du nach "Vererbung" fragst.

Viele Grüße

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

3

Freitag, 16. März 2012, 21:08

Du kannst das mit Proxys sehr leicht implementieren. Aber mir scheint in der Tat, dass du hier eher an dem Pattern hängst als an der Problemlösung. Vererbung reicht hier völlig aus, auch wenn es nicht so schick klingt. Okay, ich nenne es Inheritance. Jetzt besser?

Übrigens gibt es in Objective-C keine Konstruktoren. Du solltest dich in die Sprache einlesen.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

Beiträge: 9 887

Wohnort: Klüngelshausen

Beruf: 1,5

Hobbys: Maulaffen feilhalten, Starkstrom

  • Private Nachricht senden

4

Freitag, 16. März 2012, 21:15

Das geht in Richtung aspekt-orientierte Entwicklung. Amin hat auf seinem Macoun-Vortrag 2009 gezeigt, wie sich sowas umsetzen lässt. Wenn Dir das zuviel Aufwand ist, böte sich auch noch das Action-Target-Pattern an. Noch universeller lässt es sich wahrscheinlich über ein Proxy und NSInvocation umsetzen. Ein Beispiel dazu findest Du hier.

Es spricht aber auch nichts dagegen, das Decorator-Pattern zu verwenden. Apple setzt es ja auch ein: https://developer.apple.com/library/ios/…002974-CH6-SW43
„Meine Komplikation hatte eine Komplikation.“

Apps programmieren für iPhone und iPad

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

5

Freitag, 16. März 2012, 21:31

Das geht in Richtung aspekt-orientierte Entwicklung. Amin hat auf seinem Macoun-Vortrag 2009 gezeigt, wie sich sowas umsetzen lässt. Wenn Dir das zuviel Aufwand ist, böte sich auch noch das Action-Target-Pattern an. Noch universeller lässt es sich wahrscheinlich über ein Proxy und NSInvocation umsetzen. Ein Beispiel dazu findest Du hier.

Es spricht aber auch nichts dagegen, das Decorator-Pattern zu verwenden. Apple setzt es ja auch ein: https://developer.apple.com/library/ios/…002974-CH6-SW43

Na, ja, bei "die run-Methoden der Klassen sollen das machen" ist eigentlich Dekorierung etwas überdynamisiert.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

Beiträge: 9 887

Wohnort: Klüngelshausen

Beruf: 1,5

Hobbys: Maulaffen feilhalten, Starkstrom

  • Private Nachricht senden

6

Freitag, 16. März 2012, 21:35

Ich empfinde das Decorator-Pattern eigentlich als die undynamischste Lösung, weil da ja alles hardcoded ist ;)
„Meine Komplikation hatte eine Komplikation.“

Apps programmieren für iPhone und iPad

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

7

Freitag, 16. März 2012, 21:50

Ich empfinde das Decorator-Pattern eigentlich als die undynamischste Lösung, weil da ja alles hardcoded ist ;)

Äh, eigentlich nicht.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

Beiträge: 9 887

Wohnort: Klüngelshausen

Beruf: 1,5

Hobbys: Maulaffen feilhalten, Starkstrom

  • Private Nachricht senden

8

Freitag, 16. März 2012, 21:58

Der Decorator funktioniert nur mit der run-Methode. AOP oder eine Proxy-Lösung kannst Du beliebige Methoden anwenden.
„Meine Komplikation hatte eine Komplikation.“

Apps programmieren für iPhone und iPad

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

9

Freitag, 16. März 2012, 22:04

Der Decorator funktioniert nur mit der run-Methode. AOP oder eine Proxy-Lösung kannst Du beliebige Methoden anwenden.

Decortion ist ein Patter. Das funktioniert nicht nur mit einer Methode. Seine Problemstellung ist nur auf die run-Methode bezogen. Deshalb sage ich ja, dass Decoration überdynamisiert ist. Sein Problem ist statisch, nicht Decoration.

Dynamik hat auch nichts damit zu tun, worauf du es anwendest, sondern, wann du die Entscheidung triffst.

Jetzt nehmen wir mal die von dir genannten und verwiesenen Beispiele:

Mein AOP: Dynamisch
Delegation: Dynamisch
Proxys: Dynamisch
Action-Target: Dynamisch.
Kategorien: Statisch.
Fast alle von dir genannte Mittel der Dekoration sind dynamisch.

Was sagt Wiki: "die Dekorierer können zur Laufzeit und sogar nach der Instanzierung ausgetauscht werden." Wieder eindeutig dynamisch.

Das einzige, was in Objective-C statisch ist, sind Klassenhierarchien einschließlich Protokollen und Kategorien.

Wie gesagt: Dekoration ist außerordentlich dynmisch. Sein Problem ist statisch. Deshalb ist Dekoration überdynamisiert für sein Problem.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

Beiträge: 9 887

Wohnort: Klüngelshausen

Beruf: 1,5

Hobbys: Maulaffen feilhalten, Starkstrom

  • Private Nachricht senden

10

Freitag, 16. März 2012, 22:06

Wir reden mal wieder über unterschiedliche Dinge. Tschüss.
„Meine Komplikation hatte eine Komplikation.“

Apps programmieren für iPhone und iPad

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

11

Freitag, 16. März 2012, 22:06

Wir reden mal wieder über unterschiedliche Dinge. Tschüss.

Was meinst du denn anderes mit Decoration als die Wiki oder die Apple-Doku?
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

12

Sonntag, 18. März 2012, 15:38

Ich finde den Ansatz mit der AOP sehr gut und es würde sicherlich mein Problem lösen - aber Ihr habt wahrscheinlich Recht dass es etwas zu viel des Guten ist. Auf jeden Fall ein sehr interessanter und unterhaltsamer Vortrag.

Mit Vererbung (mag es gerne in Deutsch - also nicht nötig es Inheritance zu nennen ;-)) geht es natürlich auch. Aber: der Code bleibt leserlicher und ist einfacher testbar wenn ich das Objekt - welches in seiner Funktionalität erweitert werden soll - dekoriere anstatt es über Vererbung zu lösen. So meine bisherige Erfahrung -> allerdings in anderen Sprachen.

Der Einsatz eines Proxies leuchtet mir zunächst nicht ein, da ich kein Objekt brauche welches eine Stellvertreterfunktion einnimmt solange das Originalobjekt nicht verfügbar ist. Will ja eine reine Erweiterung des bestehenden Codes haben indem ich vor der Ausführung von run() allen Interessierten ein preRun() sende und danach ein postRun().

AOP umgesetzt mit Proxies: http://blog.jayway.com/2009/03/06/proxy-…for-cocoa-touch

Vielleicht doch der richtige Weg - auch wenn ich's noch nicht wirklich verstehe.

13

Sonntag, 18. März 2012, 16:01

Will ja eine reine Erweiterung des bestehenden Codes haben indem ich vor der Ausführung von run() allen Interessierten ein preRun() sende und danach ein postRun().

Das klingt mehr nach einem

C/C++-Quelltext

1
2
3
4
5
6
-(void) myRunMethod
{
    [myApplicationDoingRunStuffNotificationCenter postNotificationName:@"runMethodWillStartNotification" object:self];
    // Deine Implementierung der Run-Methode
    [myApplicationDoingRunStuffNotificationCenter postNotificationName:@"runMethodDidEndNotification" object:self];
}


Und alles, was irgendwie irgendwo an irgendeinem Notification Center hängt und auf runMethodWillStartNotification oder runMethodDidEndNotification lauscht wird darüber informiert, dass deine Methode gerade irgendwas macht.
Daraufhin kann es dann eigenständig auf Grund seiner Programmierung festlegen, was es mit diesen Informationen anfangen will.

Vergleiche
Notification Programming Guide
NSNotification Class Reference
Hilfreich? Dann freue ich mich über eine kleine Spende. :) Flattr this
----
«Applejack» "Don't you use your fancy mathematics to muddle the issue!"
----

Beiträge: 9 887

Wohnort: Klüngelshausen

Beruf: 1,5

Hobbys: Maulaffen feilhalten, Starkstrom

  • Private Nachricht senden

14

Sonntag, 18. März 2012, 16:03

Der Einsatz eines Proxies leuchtet mir zunächst nicht ein, da ich kein Objekt brauche welches eine Stellvertreterfunktion einnimmt solange das Originalobjekt nicht verfügbar ist. Will ja eine reine Erweiterung des bestehenden Codes haben indem ich vor der Ausführung von run() allen Interessierten ein preRun() sende und danach ein postRun().

Ein Proxy sind relativ einfach zu basteln. Ohne Auswertung des Returnwertes geht es ungefähr so:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface LoggingProxy 

@property (nontatomic, strong) id target;

@end

@implementation LoggingProxy

@synthesize target;

- (id)forwardInvocation:(NSInvocation *)inInvocation {
    NSLog(@"start %@", NSStringFromSelector(inInvocation.selector);
    [inInvocation invokeWithTarget:self.target];
    NSLog(@"end %@", NSStringFromSelector(inInvocation.selector);
}

Das kannst Du dann beispielsweise so verwenden:

Quellcode

1
2
3
id theProxy = [[LoggingProxy alloc] init];
theProxy.target = ...;
[theProxy run];
„Meine Komplikation hatte eine Komplikation.“

Apps programmieren für iPhone und iPad

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

15

Sonntag, 18. März 2012, 20:00

Ich finde den Ansatz mit der AOP sehr gut und es würde sicherlich mein Problem lösen - aber Ihr habt wahrscheinlich Recht dass es etwas zu viel des Guten ist. Auf jeden Fall ein sehr interessanter und unterhaltsamer Vortrag.

Mit Vererbung (mag es gerne in Deutsch - also nicht nötig es Inheritance zu nennen ;-)) geht es natürlich auch. Aber: der Code bleibt leserlicher und ist einfacher testbar wenn ich das Objekt - welches in seiner Funktionalität erweitert werden soll - dekoriere anstatt es über Vererbung zu lösen. So meine bisherige Erfahrung -> allerdings in anderen Sprachen.

Der Einsatz eines Proxies leuchtet mir zunächst nicht ein, da ich kein Objekt brauche welches eine Stellvertreterfunktion einnimmt solange das Originalobjekt nicht verfügbar ist. Will ja eine reine Erweiterung des bestehenden Codes haben indem ich vor der Ausführung von run() allen Interessierten ein preRun() sende und danach ein postRun().

AOP umgesetzt mit Proxies: http://blog.jayway.com/2009/03/06/proxy-…for-cocoa-touch

Vielleicht doch der richtige Weg - auch wenn ich's noch nicht wirklich verstehe.

Wenn du es sauber machen willst, ist AOP schon richtig. Was dich stört, ist, dass das Logging ein Cross-Concern ist. Dafür ist AOP erfunden worden. Du willst das, willst es aber nicht. ;-)

Ja, man kann das mit Proxys machen. Deshalb wude das hier ja auch erwähnt. Aber das ist dann kein wirkliches AOP mehr. Dort taucht das Proxy bei der Erzeugung auf. Ich will nicht sagen, dass das die Kindergartenlösung ist, aber sie bekommt auch keinen Doktorgrad.

Für dein Problem ist Subclassing absolut okay.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

Beiträge: 19 427

Wohnort: Köln

Beruf: Rechtsanwalt

Hobbys: FSK18

  • Private Nachricht senden

16

Sonntag, 18. März 2012, 20:08

Der Einsatz eines Proxies leuchtet mir zunächst nicht ein, da ich kein Objekt brauche welches eine Stellvertreterfunktion einnimmt solange das Originalobjekt nicht verfügbar ist. Will ja eine reine Erweiterung des bestehenden Codes haben indem ich vor der Ausführung von run() allen Interessierten ein preRun() sende und danach ein postRun().

Ein Proxy sind relativ einfach zu basteln. Ohne Auswertung des Returnwertes geht es ungefähr so:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface LoggingProxy 

@property (nontatomic, strong) id target;

@end

@implementation LoggingProxy

@synthesize target;

- (id)forwardInvocation:(NSInvocation *)inInvocation {
    NSLog(@"start %@", NSStringFromSelector(inInvocation.selector);
    [inInvocation invokeWithTarget:self.target];
    NSLog(@"end %@", NSStringFromSelector(inInvocation.selector);
}

Das kannst Du dann beispielsweise so verwenden:

Quellcode

1
2
3
id theProxy = [[LoggingProxy alloc] init];
theProxy.target = ...;
[theProxy run];

Das reicht nicht.

Ein paar Beispiele:

[object respondsToSelector:@selector( aMethodIntheBackend )] // Unerwartetes Ergebnis

Original *orignal = … // Verproxyed oder wie man das schreibt
[original isKindOfClass:[Original class]]; // Unerwartetes Ergebnis
[original class]; // Liefert Proxyklasse statt Originalklasse

[orignal release]; // Memory-Leak Du verwendest ARC.
Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
verhindert man die Leaks, so verhindert man auch die Begrenzung auf 128 Abfragen

17

Montag, 19. März 2012, 00:25

@worker: Schau dir mal 'protocol' in Objective-C an. Das könnte in die Richtung gehen, die du anpeilst ... Mir hat sich da der Vergleich zu Interfaces in anderen C-Sprachen angeboten.
MfG, blue

Social Bookmarks