ObjectiveCeeds › Cocoa Designpattern: Class Cluster

Cocoa Designpattern: Class Cluster

Von Manfred Kreß
Die Implementation
Seite 3 von 3



Zeit einen Blick in die Implementation von OCNumber zu werfen: OCNumber.m
#import "OCNumber.h"
#import "OCNumberPlaceholder.h"
#import "OCNumberInteger.h"
#import "OCNumberFloat.h"


@implementation OCNumber

+ (id) allocWithZone: (NSZone *)zone
{
	return NSAllocateObject([OCNumberPlaceholder class], 0, zone);
}

- (id) initWithInt: (int)value
{
	[self release];
	self = nil;
	self = [[OCNumberInteger alloc] initWithInt: value];
	return self;
}
- (id) initWithFloat: (float)value
{
	[self release];
	self = nil;
	self = [[OCNumberFloat alloc] initWithFloat: value];
	return self;
}

- (int) intValue
{
	return 0;
}
- (float) floatValue
{
	return 0.0;
}
@end
+ (id) allocWithZone: (NSZone *)zone reserviert keinen Speicher für OCNumber sondern für OCNumberPlaceholder. So wird sichergestellt, das niemals ein OCNumber Objekt initialisiert wird, denn das stellt ja nur das Interface zur Verfügung, welches dann von den Subklassen implementiert wird. Um eine endlose Rekursion zu verhindern, wird der Speicher nicht über die Klassenmethoden allociert, sonder über die C Funktion NSAllocateObject. In den Initializern wird dann self zunächst released (das ist der Platzhalter) und anschließend wird self eine Instanz der entsprechenden Subklasse, die dieser Initializer erzeugen muss, zugewiesen und zurück gegeben. That‘s the Magic. Nun noch die Implementation unserer beiden Subklassen für int und float: OCNumberInteger.m
#import "OCNumberInteger.h"

@implementation OCNumberInteger

+ (id) allocWithZone: (NSZone *)zone
{
	return NSAllocateObject([OCNumberInteger class], 0, zone);
}
- (id) initWithInt: (int)value
{
	self = [super init];
	if (self != nil)
	{
		_OCInteger = value;
	}
	return self;
}
- (id) initWithFloat: (float)value
{
	[self release];
	return nil;
}

- (int) intValue
{
	return _OCInteger;
}
- (float) floatValue
{
	return (float)_OCInteger;
}

@end
Auch hier wird allocWithZone: überschrieben um eine Rekursion zu verhindern. Allerdings wird nun wirklich Speicher für die entsprechende Klasse reserviert. initWithInt: ist dann ein klassischer Initializer, der value der Instanzvariablen zuweist. initWithFloat: gibt nil zurück. Dieser Fall sollte aber nie eintreten, da OCNumber immer dafür sorgt, daß das richtige Objekt initialisiert wird. intValue und floatValue casten dann entsprechend den gespeicherten Wert vor der Rückgabe. Entsprechend OCNumberFloat: OCNumberFloat.m
@implementation OCNumberFloat

+ (id) allocWithZone: (NSZone *)zone
{
	return NSAllocateObject([OCNumberFloat class], 0, zone);
}
- (id) initWithInt: (int)value
{
	[self release];
	return nil;
}
- (id) initWithFloat: (float)value
{
	self = [super init];
	if (self != nil)
	{
		_OCFloat = value;
	}
	return self;
}

- (int) intValue
{
	return (int)_OCFloat;
}
- (float) floatValue
{
	return _OCFloat;
}

@end
Und so gibt OCNumber immer ein Objekt zurück, das für den entsprechenden Fall genau passend ist und ihn optimal implementiert. Sprich, die Speicherung der Daten optimiert. Als erste Verbesserung könnte nun description so überschrieben werden, das jede Klasse einen entsprechenden String mit dem Wert zurückgibt. Die Platzhalterklassen sollten eigentlich eine Exception werfen, wenn eine Methode aufgerufen wird. Darauf habe ich aber aus Gründen der Übersichtlichkeit verzichtet. Das komplette Projekt steht hier zum Download über Bitbucket bereit. Mit Mercurial auschecken: hg clone https://bitbucket.org/ObjectiveCeeds/clusterexample

« vorige Seite
Seite: 3 von 3


Cocoa Designpattern: Class Cluster

OCNumber
Die Implementation