Objective-C: Builder Pattern vs Configuration Objects

In the Java world the usage of the builder pattern is quite common, when you are building complex objects. The usage of a builder would look like this:

MyObject myObject = new MyObject.Builder()
        .setFoo(someFoo)
        .setBar(someBar)
        .build();

That’s easy to read! But what when you want that on the Objective-C language? The builder pattern is not too much adopted in the Objective-C Community, but as Erik’s blog shows, it is possible.

The direct “java port” would look like this:

MyObject* myObject = [[[[MyObject Builder] foo:someFoo] bar:someBar] build];

As Erik stated this is quite ugly on the syntax, because of the deeply nested method calls. The previous blog also mentions a cleaner version, by using reflection:

...
MyObject* myObject = [builder foo:someFoo bar:someBar build];

However Erik’s “reflection solution” does not work when ARC is enabled. To fix it, you have declare the functions on the interface file of the “Builder”. This can become pretty nasty, when your object has a lot’s of options to configure :-(

Configuration objects FTW

In the AeroGear project we decided against using the builder to create complex objects, like our Pipe or AuthModule. Since our JavaScript library was already using configuration objects, this felt natural for our iOS library as well. By accident I found this article that describes how to use blocks to do inline configuration. The only thing that I did not like was the fact that in the article, the caller has to create the object and again use its setters to apply the different options inside of the block.

For our library we want the properties to be immutable /readonly. So our create function just takes a block with a configuration object. To continue using the above example, the final result would read like this:

...
MyObject* myObject = [builder create:^(ConfigObject* config) {
    [config foo:@"foo"];
    [config bar:@"bar"];
    // apply more options...
    ...
}];

How does it work?

In the last snippet the builder object’s create function has one argument: a block that takes configuration object! Inside of the block, we use the given configuration object to apply the desired arguments. NOTE: There is no extra work to create the config object, that’s done by the library. A caller of the create function just needs to apply the different options!

More code

Inside of the create function implementation, the configuration object (with its default settings) is created and passed into the block call. Once the block is completed the configuration object is read in order to create the MyObject instance:

-(MyObject*) create:(void (^)(ConfigObject)) configBlock {

    ConfigObject* theConfigObj = [[ConfigObject alloc] init];

    if (configBlock) {
        configBlock(theConfigObj);
    }

    // read the config...
    NSString* foo  = [theConfigObj foo];

    ....
    return myObject;
}

Once the block invokation returns, the values are read and the concrete MyObject instance is being build!

Enjoy!

About these ads

Howdy!

Posted in aerogear

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 33 other followers

%d bloggers like this: