In our last blog, we learned about the gamma categorization, and it states that we have 3 major categories that are “Creational”, “Structural” and “Behavioral”, In this blog, we will discuss the first important pattern under the “Creational” category, i.e., “Builder Pattern."
Why Builder Pattern?
Sometimes, it is very easy to create an object; you just have to call a single constructor to achieve that, but sometimes you have to consider some special cases where you have to be very particular about object creation, otherwise it will lead to an error unknowingly. Let's use an example to better understand this. Let's say you want to create a paragraph using a long string, but you can't just use the string class constructor because that will be very difficult to maintain. Instead, you should try using the StringBuilder class, which enables us to create a string by adding shorter pieces to the one that already exists.
Additionally, having a large number of constructor parameters can be problematic because people may become confused or make mistakes when passing so many parameters to a single constructor. Instead, we should give users a way to create objects piece by piece, which is what the Builder pattern does. It offers users a better piece-by-piece approach or API so that they can create objects without any trouble.
Let’s look at an example, and let’s try to understand what problem the Builder Pattern solves for us.
using System.Text;
namespace DesignPatterns.BadBuilderPattern
{
public class BuilderPattern
{
public static void Main(string[] args)
{
Dictionary<string, string> map = new Dictionary<string, string>
{
{"user","admin" }, {"email","admin@test.com" }
};
var sb = new StringBuilder();
sb.AppendLine("{");
foreach (var item in map)
{
sb.Append("\t{").AppendFormat("0:1"), item.Key, item.Value AppendLine("},");
}
sb.AppendLine("}");
Console.WriteLine(sb);
}
}
}
As you can see, we are attempting to build a JSON object from the dictionary here, but we are already using C# code, which is fine for small use cases, but what if we later needed to construct large objects? In that scenario, we need some robust solution to build a JSON object, and we need some sort of “JsonBuilder” to remove the duplication in code and to provide an API with which we can build complex JSON objects.
namespace DesignPatterns.GoodBuilderPattern
{
using System.Text;
public class JsonRoot
{
private string _name = string.Empty;
public List<JsonPair> Children = new List<JsonPair>();
public JsonRoot(string Name)
{
_name = Name;
}
public string AsString()
{
var sb = new StringBuilder();
sb.AppendLine("{");
sb.AppendFormat("\t{0}: ", _name). AppendLine("{");
foreach (var c in Children)
{
sb.Append("\t\t{");
sb.AppendFormat(" {0} : {1} ", c.Key, c.Value).Append(" },"). AppendLine();
}
sb.AppendLine("\t}");
sb.AppendLine("}");
return sb.ToString();
}
}
public class JsonPair
{
public string Key = string.Empty;
public string Value = string.Empty;
}
public class JsonBuilder
{
private JsonRoot _root;
private string _rootName;
public JsonBuilder(string RootName)
{
_rootName = RootName;
_root = new JsonRoot(RootName);
}
public JsonBuilder AddKeyValuePair(string Key, string Value)
{
_root.Children.Add(new JsonPair
{
Key = Key,
Value = Value
}
);
return this;
}
public JsonBuilder Clear()
{
_root = new JsonRoot(_rootName);
return this;
}
public string PrintJson()
{
return _root.AsString();
}
}
public class BuilderPattern
{
public static void Main(string[] args)
{
var jb = new JsonBuilder("entries");
jb.AddKeyValuePair("user", "admin");
jb.AddKeyValuePair("email", "admin@user.com");
jb.AddKeyValuePair("hobbies", "['dancing', 'singing']");
Console.WriteLine(jb.PrintJson());
}
}
}
As you can see, we now have a reliable "JsonBuilder" class that allows us to create any type of JSON object.
Are we done with “builders”?
Not really. There are several considerations we must make when implementing the builder pattern, some of which will be covered in upcoming blogs. Additionally, there are several ways to create builders, so we will also cover those as well, so stay tuned!
At the conclusion, I'll say that the Builder pattern is a crucial one because it enables us to expose meaningful APIs by enclosing existing functionality. It is also used in C# because, as we all know, the "StringBuilder" class in C# uses the Builder pattern to create strings without allocating memory each time, improving performance.
Happy Coding…!!!
Top comments (0)