
Protocol-Oriented Builder Pattern in Swift
I am an avid user of the Builder Design Pattern for creating and validating models. Why? It makes model creation dead simple.
let user: User? = UserBuilder()
.set(field: .firstName("Matt"))
.set(field: .lastName("Hoffman"))
.set(field: .username("mhoffman"))
.build()When I create models, I usually don’t know if the values I am passing in are valid or not; therefore, I cannot simply create the model. I have to write a lot of logic before creating the model to validate the fields. If you are used to writing this validation outside of the model (i.e. in the controllers), then you will find that you duplicate code, and you will probably miss error cases for the sake of speed. Models aren’t created in only one place; they are created when reading JSON from network requests, and in various views, when you create a model from user input to use in other parts of your app, this leaves a lot of room for error.
The Builder Pattern solves the problem of duplicated code, but it still requires you to think carefully about all of the validation that happens in the build() phase. And writing each set() function for each field is extremely tedious. What if I told you someone spent a couple of days making the Builder Pattern simpler to implement, and much easier to include all the validation logic needed for a model? It’s your lucky day!
The Ye Old Way
Let’s say you have a UserSignUp object with fields firstName,lastName, username, password, confirmPassword, where lastName is not required. This is how I used to write the Builder Pattern:
The above way is clean, and viable. If you are new to the Builder Pattern, go ahead and use it! The protocol-oriented way I’m going to describe next actually requires a little more code, but it ends up making the validation logic clearer and when adding new fields, the compiler will warn you about validation cases you have not handled through the power of enums.
The New Way
That’s it! As you see, there is definitely more code in the Protocol-Oriented Builder Pattern, rather than simply making a custom Builder with no reused code for each Model. However, whenever you add a field to the Protocol-Oriented pattern the compiler will complain if you don’t specify the field’s validation and isRequired. Additionally, with this approach, it becomes very clear where to add your model’s validation logic. Finally, the code reuse is nice, and if other methods need to be added for validation, it can work for all of your builders!
Now, Your Turn
Now, if you love the approach I took to the Builder Pattern in Swift, I implore you to go use it in your project and reap the rewards. Then, as you come across improvements, let me know!
Else, if you think I overcomplicated things and you have an alternative approach, or you simply know more Swift than I do and can improve this code, I would love the feedback.
TL;DR
Using the Builder Pattern makes models powerful in Swift. I made a Protocol-Oriented implementation that you can find here.