Configuration Objects: Delegate Initialization to a Parameter

The Builder design pattern is often overlooked, I find. Apart from plain builders, in Ruby I found that some us it like a configurator. You can use a configuration object in Swift in the for of block parameters, for example:

thing = ComplexThing() { config in
    config.boringProperty = 123
    config.addThing(foo)
}

This would make the internals of ComplexThing configuratable through the block. Instead of messing around with an instance of a ComplexThing, you can do atuff with the configurator which determines how the instance will look.

class ComplexThing {
    
    class Builder {
        var boringProperty: Int
        var interestingList = [OtherThing]()
        
        func addThing(thing: OtherThing) {
            interestingList.append(thing)
        }
    }
    
    let property: Int
    let things: [OtherThing]

    init(config: (ComplexThing.Builder) -> Void) {
        
        let builder = ComplexThing.Builder()
        config(builder)
        
        self.property = builder.boringProperty
        self.things = builder.interestingList
    }
}

You see, the utility of this approach in my day-to-day life is not very clear, yet, or I’d have come up with a better example.

Say you have 2+ server configurations and would like to setup a connection according to these – why shouldn’t you store these configurations in a value object from which the connection reads and populates its attributes? The only difference is querying for values VS setting values.

I am not a friend of dogmatism, so even though I emphasize the utility of East-Oriented Programming, you shouldn’t just use this pattern because it’s “East” while making things harder to read.

Will post an update if I find a good real-world use case.

Browse the blog archive