2012-05-10 4 views
9

Angenommen, ich mache eine Objective-C-Klasse, die einen Bruch darstellt, und möchte unveränderliche und veränderbare Versionen erstellen.Was ist der effizienteste Weg, um unveränderliche und veränderbare Versionen einer objective-c-Klasse zu machen?

Nach den Mustern im Foundation-Framework können Sie erwarten, dass die Methode fractionByAddingFraction: in der unveränderlichen Version und addFraction: in der änderbaren Version angezeigt wird.

Das Paradoxon, auf das ich stoße, ist, wie man nur die Bruchteil-addierende Logik einmal zwischen den zwei Klassen einschließt. Es scheint, dass die unveränderliche fractionByAddingFraction: Methode über die veränderbare addFraction: Methode wissen muss (und diese nutzen muss), um Code Duplikation zu vermeiden, und dennoch die veränderbaren Methoden in die Implementierung der unveränderlichen Klasse einbeziehend bedeutet, dass sie möglicherweise auf dem unveränderlichen aufgerufen werden könnten Objekt, das den Punkt besiegt.

Eine kurze Erklärung (oder noch besser, eine Fortsetzung dieses vereinfachten Beispiels) wäre sehr zu begrüßen!

+4

Ihr Klassenbeispiel scheint ein _value-Objekt_ darzustellen, daher sollten Sie keine veränderbare Version dafür bereitstellen. __Just machen Sie es unveränderlich .__ –

+0

@ Jordão Für dieses spezielle Beispiel haben Sie recht. Ich fühlte einfach, dass dies der einfachste und prägnanteste Weg war, um meine Verwirrung über das Konzept im Allgemeinen zu erklären (wie es sich auf kompliziertere Klassen bezieht). Irgendwelche Gedanken darüber, wie es unabhängig davon gemacht würde? – user1385983

Antwort

3

Ihr Ansatz ist korrekt (wenn Sie wirklich eine veränderbare Unterklasse benötigen, die Sie vermeiden sollten, wenn Sie sie nicht wirklich brauchen). Ich bin nicht ganz klar, wo die Verwirrung hereinkommt. Sie würden am einfachsten implementieren addFraction: mit fractionByAddingFraction:. Es wäre ein wenig ineffizient, aber das ist die Richtung, die am sinnvollsten wäre. Etwas wie:

- (void)addFraction:(Fraction *)anotherFraction { 
    Fraction *newFraction = [self fractionByAddingFraction:anotherFraction]; 
    self.internalStuff = newFraction.internalStuff; 
} 

Aber in der Regel würden Sie wahrscheinlich dieses effiziente mit einiger privaten _GetInternalStuffByAddingInternalStuffs() Funktion behandeln, die beiden Klassen verwenden würden.

+0

Danke für die Vorschläge. Ich hatte den ersten Ansatz vermieden, weil, wie Sie bereits erwähnt haben, es ineffizient sein kann, jedes Mal ein neues Objekt zu erstellen, wenn eine seiner Komponenten geändert wird. Ihre Idee, eine private Funktion zu machen, scheint eine gute Alternative zu sein, aber ich frage mich, wo die Funktion im Idealfall für Implementierungen beider Klassen zugänglich wäre, aber für alles andere unzugänglich wäre (was es ausschließt, sie in eine Kopfzeile zu setzen)? – user1385983

+0

Dies wird normalerweise mit einem privaten Header wie Fraction + Private.h getan. Beachten Sie, dass Sie die veränderbare Form immer noch ignorieren möchten, wenn es sich um eine solche Sache handelt. Beachten Sie, dass NSNumber keine änderbare Form hat. Wenn Sie nicht viele von ihnen sehr schnell erstellen, macht die Einfachheit und Thread-Sicherheit von Wertobjekten sie sehr attraktiv. Selbst wenn Sie sie sehr schnell erstellen, können Sie einige davon zwischenspeichern. NSNumber speichert die Ganzzahlen -1-12 als Singletons zwischen, wie ich mich erinnere. Sie können diese Art von Caching am einfachsten mit unveränderlichen Objekten durchführen. Aber das oben genannte ist, wie Sie damit umgehen, wenn Sie Mutabilität benötigen. –

+0

Denken Sie daran, dass Sie die zugrunde liegenden CoreFoundation-Objekte implementieren können: http://opensource.apple.com/source/CF/CF-635/CFArray.c. –

0

Die primären Implementierungen von Foundation-Sammlungen betrügen: Es gibt nur eine Implementierung, die eine Unterklasse von NSMutableFoo ist, und sie hat ein privates Veränderbarkeits-Flag. Dies bedeutet, Client-Code kann nicht testen, ob ein bestimmtes Objekt veränderbar ist oder nicht, aber das wäre sowieso nie eine gute Idee außer vielleicht für Debugging und Assertions.

+0

Verstehe ich richtig, dass "NSFoo" eine Unterklasse von "NSMutableFoo" wäre, und dass "NSMutableFoo" alle Methoden für beide Klassen enthalten würde, jedoch die Fähigkeit der unveränderlichen Unterklasse einschränken würde, die veränderbaren basierend auf dem privaten Flag zu verwenden? – user1385983

+0

'NSFoo' ist keine Unterklasse von' NSMutableFoo', nein. Die Beziehung ist im Allgemeinen "NSFoo" ← "NSMutableFoo" ← "NSCFFoo", wobei "NSCFFoo" eine konkrete Implementierung ist. 'NSCFFoo's Mutationsmethoden überprüfen das veränderbare Flag und werfen eine Ausnahme aus, wenn es unveränderlich ist. (Die Realität ist tatsächlich komplexer, weil gebührenfreie Überbrückungen erforderlich sind, aber so würde es funktionieren, ohne dass CF involviert ist.) Für Ihre eigenen Klassen würden Sie die konkrete Unterklasse wahrscheinlich so etwas wie 'XYConcreteFoo' nennen. –