When to Use the Builder Design Pattern
Have you ever looked back at old code you wrote and asked yourself, "Why did I do it that way?" I do that quite a bit and found myself doing just that on the open source project VoiceModel that I coordinate and contribute to. I think it is healthy to question your method of coding as it can lead to refactoring that makes the code easier to understand and maintain, to name just a few benefits of refactoring.
The section of code in question had to do with how states where created in a state machine. VoiceModel has a built-in state machine that make it easy to build voice application call flows. You add states to the state machine that represent actions like playing a prompt to the user or get input from the user from a telephone keypad or using speech recognition. These states are specific to the voice part of the application, but you can also have states that perform background operations, such as a query a database. The states that are used for voice needed to be wired a certain way so I thought this seems like a good place to use the Builder Design Pattern.
The Builder Design Pattern is a method for creating objects that require a different implementations. So here is how I implemented this pattern in VoiceModel.
When reviewing this code I realized this was not a very complex Builder and perhaps I could handle this just as well using inheritance. Here is what I came up with.
Now I can create a State specific for Voice by doing this.
I kind of like this new implementation and think it is easier to understand. But the exercise raised a lot of questions for me. When should you use the Builder Design Pattern and when should you just use inheritance? Is this an abuse of using inheritance since I did not add any new properties or methods to the derived class? Is this just another way of implementing the Builder Design Pattern, and what are the pros and cons?
I bet from the title you thought I would provide you with the definitive answer to this question. I was hoping the readers of this would provide their insight on this design pattern through comments and we could all come to a consensus. What are your thoughts?
Here are some of my initial thoughts. The original impetus for creating the builder was to make it easier for developers to create voice states in a single line of code and not having to remember to add the VoiceModel to the State. Both implementation achieve this goal. The builder makes it clear that we are creating the same type of object with the its properties configured differently. This is kind of obfuscated by using a derived class which implies it has different properties and/or methods. Maybe I just need to refactor the name of the builder to StateBuilder.BuildVoice. Sometimes you did do it right the first time and you just over think it.
The section of code in question had to do with how states where created in a state machine. VoiceModel has a built-in state machine that make it easy to build voice application call flows. You add states to the state machine that represent actions like playing a prompt to the user or get input from the user from a telephone keypad or using speech recognition. These states are specific to the voice part of the application, but you can also have states that perform background operations, such as a query a database. The states that are used for voice needed to be wired a certain way so I thought this seems like a good place to use the Builder Design Pattern.
The Builder Design Pattern is a method for creating objects that require a different implementations. So here is how I implemented this pattern in VoiceModel.
public class ViewStateBuilder { public static State Build(string Id, string target, VoiceModel vm) { State vState = new State(Id, target); vState.DataModel = vm; return vState; } public static State Build(string Id, VoiceModel vm) { State vState = new State(Id); vState.DataModel = vm; return vState; } }I called this a ViewStateBuilder because it created a state that contained the VoiceModel needed to create the View that generated VoiceXML or JSON for Tropo. Confusing. Perhaps not the best name and not the best use of the Builder Design Pattern. Here is how you would use this builder to create a greeting in your voice application.
State greeting = ViewStateBuilder.Build("greeting", new Say("greeting", "Please take our short survey"));
When reviewing this code I realized this was not a very complex Builder and perhaps I could handle this just as well using inheritance. Here is what I came up with.
public class VoiceState : State { public VoiceState(string Id, string target, VoiceModel vm) : base(Id, target) { this.DataModel = vm; } public VoiceState(string Id, VoiceModel vm) : base(Id) { this.DataModel = vm; } }
Now I can create a State specific for Voice by doing this.
State greeting = new VoiceState("greeting", new Say("greeting", "Please take our short survey"));
I kind of like this new implementation and think it is easier to understand. But the exercise raised a lot of questions for me. When should you use the Builder Design Pattern and when should you just use inheritance? Is this an abuse of using inheritance since I did not add any new properties or methods to the derived class? Is this just another way of implementing the Builder Design Pattern, and what are the pros and cons?
I bet from the title you thought I would provide you with the definitive answer to this question. I was hoping the readers of this would provide their insight on this design pattern through comments and we could all come to a consensus. What are your thoughts?
Here are some of my initial thoughts. The original impetus for creating the builder was to make it easier for developers to create voice states in a single line of code and not having to remember to add the VoiceModel to the State. Both implementation achieve this goal. The builder makes it clear that we are creating the same type of object with the its properties configured differently. This is kind of obfuscated by using a derived class which implies it has different properties and/or methods. Maybe I just need to refactor the name of the builder to StateBuilder.BuildVoice. Sometimes you did do it right the first time and you just over think it.
Comments
Post a Comment