2012-04-12 9 views
2

Ich versuche, das Konzept der Komponentenprogrammierung beim Schreiben meines iOS-Spiels zu implementieren.Objective-C und Komponentenprogrammierung

In dem Buch „Komponentensoftware: Beyond Objektorientierte Programmierung“ von Clemens Szyperski, erwähnt er eine Taktik:

(nicht Zitat) Beginnen Sie mit einer Klasse Ente, die Komponente Quack hinzufügt. Klasse Quack implementiert eine Schnittstelle für das Objekt, das sie aufruft. Die Schnittstelle gibt eine Methode an, die Quacks verwendet quack()

Mit diesem Setup hat Duck keine Referenz oder Kenntnis über Quack, außer wenn es instanziiert ist und nie verwendet wird danach in Ente. Andere Objekte können duckObject.quack() aufrufen und Quack erreichen, während Sie nur auf das Duck-Objekt achten.

Bisher habe ich versucht, dies ohne Erfolg zu implementieren. Vorzugsweise sollte Duck nicht mehr Code als Instanziierung benötigen, der Rest sollte in Quack-Klasse platziert werden. Kann dies in Objective-C (für iOS?) Erfolgen, oder sollte ich COP lieber für andere Sprachen verwenden?

+0

Ich weiß, Sie bereits akzeptiert ein Antwort, aber haben Sie sich die Kategorien von Objective-C angesehen? Sie können eine Quack-Kategorie auf Duck implementieren, die die "-quack" -Methode hinzufügt. Die Duck-Klasse müsste sich dessen nicht bewusst sein. (Für das, was es wert ist, bin ich mit KillerX, dass dies klingt wie ein schreckliches Design Anti-Muster.) –

Antwort

1

Ich glaube nicht ein genauer Vergleich in ObjC gibt es, aber es klingt wie Sie in message forwarding suchen. Wenn einem Objekt eine Nachricht gesendet wird, auf die es nicht reagiert, unmittelbar bevor ein Fehler gemeldet wird, sendet die Laufzeitumgebung das Objekt forwardInvocation: mit einem NSInvocation-Argument, das die Nachricht und die Argumente einkapselt.

In forwardInvocation: kann ein Objekt den Aufruf an ein anderes Objekt weitergeben, das behandelt diese Nachricht verarbeitet. Dies ermöglicht eine Duck Instanz auf die Nachricht zu antworten quack, obwohl quack nicht durch Duck implementiert wird, durch einen Verweis auf eine Instanz Quack hält, was es nicht implementiert:

- (void)forwardInvocation:(NSInvocation *)anInvocation 
{ 
    if([myQuack respondsToSelector:[anInvocation selector]]){ 
     [anInvocation invokeWithTarget:someOtherObject]; 
    } 
    else{ 
     [super forwardInvocation:anInvocation]; 
    } 
} 
+0

Vielleicht ist der falsche Ort, um dies zu fragen (mehr CS), aber hier gehen wir jeden Weg: Wäre es sinnvoll, eine Menge/Array von Objekten (Komponenten) zu haben, und Sie über sie mit repliesToSelector: und feuern Sie auf der ersten gefunden? Hat jemand eine Idee, welche Art von Performance-Hit das wäre (natürlich, je mehr Objekte du hast ...)? – KillerX

+0

@Killer: Sicher, du könntest das tun. Ich kann nicht sagen, was der Performance-Hit wäre; Sie verursachen die Kosten von n + 1 message sends ('repliesToSelector:' * n, dann 'invokeWithTarget:'), aber Message-Sends sind nicht wirklich so langsam, wie alle denken, dass sie es sind. Ich wäre mehr besorgt über die Design-Implikationen eines Objekts, das vorgibt, dass es auf eine ganze Reihe von anderen Klassenmethoden reagiert. –

+0

Ja, das ist wahr, wenn nichts anderes Xcode Ihnen wahrscheinlich eine Gazillion Warnungen geben würde, so würden echte Probleme im Lärm verloren gehen + niemand würde wirklich in der Lage sein zu sagen, welche Selektoren das Ding anspricht. Um es weiter in ein Antipattern zu erweitern: "Yay, Sie können Objekte dynamisch zur Laufzeit mit anderen Objekten erweitern!" :) Man könnte sogar so weit gehen, ein "generisches" Objekt zu schreiben, das nur seine volle Funktionalität durch Hinzufügen von Modulen zur Laufzeit erhält. (Für alle, die dies in Betracht ziehen: BAAAAAAD IDEA !!!!) – KillerX

0

Nicht wirklich sicher, was Ihre Frage ist. Es klingt, als wolltest du einen schwachen Bezug zu einer Klasse haben. Zuerst wird die Ente Klasse

//Duck.h 
#import "Quack.h" 

@interface Duck : NSObject { 
    Quack *quacker; 
} 

@property (nonatomic, retain) Quack *quacker; 

@end 

//Duck.m 

@implementation Duck 
@synthesize quarker; 

-(id) init { 
    self = [super init]; 

    if(self) { 

    } 

    return self; 
} 

-(Quack *)quacker { 
    if(quacker == nil) { 
     [self setQuacker:[[[Quack alloc] init] autorelease]]; 
    } 

    return quacker; 
} 

@end 

dann die Quack Klasse implementieren.

//Quack.h 

@interface Quack : NSObject { 

} 

-(void)quack; 

@end 

//Quack.m 

@implementation Quack 

-(id) init { 
    self = [super init]; 

    if(self) { 

    } 

    return self; 
} 

-(void)quack { 
    NSLog(@"quack"); 
} 
@end 

Nun wie auch immer Klasse, die Sie wollen:

//RandomClass.m 
[[[self duck] quacker] quack]; 
+0

Was ich suche ist irgendwie die Funktionalität der Komponente in ihr Besitzer zu implementieren, ohne dass der Besitzer bewusst ist, was Komponente tut es. Ihre Lösung, die immer noch eine schwache Referenz ist, nimmt an, dass Quack von Duck bekannt ist. Das versuche ich zu vermeiden :) –

+0

Ich sehe nicht, wie das vorteilhaft ist. Sie können eine Eigenschaft vom Typ "id" erstellen und sie einem "Quack" -Objekt außerhalb von "Duck" zuweisen. Es gäbe keinen Bedarf an Importen und "Duck" würde nicht wissen, was das ist oder was es tun könnte. – ColdLogic

+0

Ich vermasselte. Was ich meinte war, dass Quacks sich eintut, quack(), sollte Duck nicht kennen. Die Gründe, warum ich es bauen möchte, ist ... Neugier für einen. Zu Lernzwecken, warum sollte das nicht gemacht werden? –

Verwandte Themen