This website does not display correctly in Internet Explorer 8 and older browsers. The commenting system does not work either in these browsers. Sorry.

erik dörnenburg

Builder pattern in Objective-C

01 November 2011

Posted in Coding

Over the past few months I've spent a fair bit of time on a project using my MacBook Pro for development. This got me to run CCMenu again and, perhaps predictably, made me work on that in the evenings. While doing some long overdue refactorings I came across the need to construct domain objects in unit tests. So far I had used simple helper methods in the unit test itself, but the Java/Scala project I was on during the day made heavy use of the Builder pattern with fluent interfaces, and that got me thinking.

In the end I've come up with three variations of the Builder pattern in Objective-C, all of which have their pros and cons. In this post I want to show these patterns and invite comments on which one you prefer.

Before going into the detail, though, let's agree on what we're trying to build. It doesn't really matter, so let's pick cars, with properties such as make and model, plus the name of the current owner. To make it a bit harder, let's make the make and model properties immutable. The interface looks like this:

@interface Car
{
    NSString *model;
    NSString *make;
    NSString *owner;
}

- (id)initWithMake:(NSString *)aMake andModel:(NSString *)aModel;
- (NSString *)make;
- (NSString *)model;
- (void)setOwner:(NSString *)anOwner;
- (NSString *)owner;

@end

Classic Java style

A direct translation of the classic Java builder pattern would give us a class something like the following. Note that the builder provides defaults for the values in case they are not set.

@interface CarBuilder
{
    NSString *make;
    NSString *model;
    NSMutableDictionary *properties;
}

- (CarBuilder *)withMake:(NSString *)aMake;
- (CarBuilder *)withModel:(NSString *)aModel;
- (CarBuilder *)withOwner:(NSString *)anOwner;  
- (Car *)build;

@end
- (id)init
{
    [super init];
    model = @"VW";
    make = @"Golf";
    properties = [[NSMutableDictionary dictionaryWithObjectsAndKeys:@"Fred", @"owner", nil] retain];
    return self;
}

- (CarBuilder *)withMake:(NSString *)aMake
{
    make = [aMake retain];
    return self;
}

- (CarBuilder *)withModel:(NSString *)aModel
{
    model = [aModel retain];
    return self;
}

- (CarBuilder *)withOwner:(NSString *)anOwner
{
    [properties setObject:anOwner forKey:@"owner"];
    return self;
}

- (Car *)build
{
    Car *car = [[[Car alloc] initWithMake:make andModel:model] autorelease];
    [car setValuesForKeysWithDictionary:properties];
    return car;
}

@end

The usage is straight-forward:

Car *theCar = [[[[builder
                    withModel:@"Beetle"]
                    withOwner:@"Alice"]
                    build];

What I like about this approach is its simplicity. What's not so great is that the calls to the builder are deeply nested. In addition, in the builder we have to declare several variables and, if we cared about not leaking memory in tests, we'd have to add even more code to handle the assignments.

By the way, the use of a dictionary for the mutable properties makes not much sense in this case. It shines once you have more than a couple of properties as it reduces the number of variables and the number of calls in the build method. This is why I've shown this little pattern here.

Using categories

Objective-C has categories and that opens up a different possibility for writing builders. Instead of building up the state in a builder object in order to create the real object at the end, we create the object upfront and then set the properties on it, using a category. The code looks like this:

@interface CarBuilder

- (id)car;

@end

@interface Car(BuilderAdditions)

- (Car *)withMake:(NSString *)aMake;
- (Car *)withModel:(NSString *)aModel;
- (Car *)withOwner:(NSString *)anOwner;

@end
@implementation CarBuilder

- (id)car
{
    Car *car = [[[Car alloc] initWithMake:@"VW" andModel:@"Golf"] autorelease];
    [car setOwner:@"Fred"];
    return car;
}

@end  

@implementation Car(BuilderAdditions)

- (Car *)withMake:(NSString *)aMake
{
    make = [aMake retain];
    return self;
}

- (Car *)withModel:(NSString *)aModel
{
    model = [aModel retain];
    return self;
}

- (Car *)withOwner:(NSString *)anOwner
{
    [self setOwner:anOwner];
    return self;
}

@end

The usage is near idential, with the invocation of car at the beginning of the chain replacing the call to build at the end.

Car *theCar = [[[[builder car]
                    withModel:@"Beetle"]
                    withOwner:@"Alice"];

An advantage of this solution is that the builder class is just one method long and doesn't grow as we add more properties. In fact, if we don't care about defaults, this style would work without any builder class at all. We also don't need duplicate variables for holding on to the values and, lastly, by using category methods the builder code lives inside the object and thus we have more liberty to access and manipulate the internal structures. This can be good and bad, I guess.

Using reflection

Looking for a solution that doesn't touch the Car class, that avoids deep nesting of method calls during the build, and that scales well with regards to the builder code size in relation to the number of attributes, I turned to reflection.

Starting with the usage, this builder is used as follows:

Car *hotHatch = [builder carWithMake:@"VW"
                            withModel:@"Golf GTI"
                            withOwner:@"Bob"];

It is possible to give the properties in different sequences and to leave off properties:

Car *theBeetle = [builder carWithOwner:@"Alice" withModel:@"Beetle"];
Car *anyCar = [builder carWithOwner:@"James"];

In fact, the car prefix on the method is syntactic sugar and could be left off, too.

The implementation of this builder is as follows:

@interface CarBuilder

/* No methods declared */

@end
@implementation CarBuilder

- (NSArray *)selectorComponents:(SEL)aSelector
{
    NSArray *components = [NSStringFromSelector(aSelector) componentsSeparatedByString:@":"];
    return [components subarrayWithRange:NSMakeRange(0, [components count] - 1)];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    int argCount = [[self selectorComponents:aSelector] count];
    NSAssert(argCount < 100, @"expecting less than 100 arguments");
    char types[105] = "";
    for(int i = 0; i < argCount + 3; i++)
        strcat(types, (i == 2) ? @encode(SEL) : @encode(id));
    return [NSMethodSignature signatureWithObjCTypes:types];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSMutableDictionary *values = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"VW", @"make", @"Golf", @"model", @"Fred", @"owner", nil];
    unsigned int index = 2;
    for(NSString *component in [self selectorComponents:[anInvocation selector]])
    {
        NSRange with = [component rangeOfString:@"with" options:NSCaseInsensitiveSearch];
        NSAssert(with.location != NSNotFound, @"excpecting 'with' in selector elements");
        NSString *key = [component substringFromIndex:NSMaxRange(with)];
        id value = nil;
        [anInvocation getArgument:&value atIndex:index++];
        [values setObject:value forKey:key];
    }

    Car *car = [[[Car alloc] initWithMake:[values objectForKey:@"make" andModel:[values objectForKey:@"model"] autorelease];
    [values removeObjectsForKeys:[NSArray arrayWithObjects:@"make", @"model", nil];
    [car setValuesForKeysWithDictionary:properties];

    [anInvocation setReturnValue:&car];
}

@end

While more complex than the other ones, the implementation is pretty generic and most of the code could be moved into a generic builder base class. It is also fairly short and requires substantially less code to be added for additional properties than the other options.

Sounds perfect? There is one big drawback: the selector changes all the time and usually it would be unreasonable to declare all permutations, which means that Xcode and the compiler show warnings for every use of the builder. If anyone knows how to turn off that warning on a per-file basis...

In summary

The following table summarises the three approaches. What do you think?

Classic Java style Using categories Using reflection
Lines of code 42 33 36
Lines of code per property ~8 * ~6 * 0 **
Advantages Simple Short, internal access Generic, very short
Drawback Lots of code Changes object Compiler warning

* worse if we are strict about memory leaks
** if we break lines for formatting: 1-2

Comments

Starting commenting system. This can take a moment.