Builder Design Pattern Implementation
Business Requirement :
Provide an option to choose and build configuration of the system which is allocated to the employees. The configuration options that user can choose are RAM, HDD, USB Mouse etc. Choose the system configurations based on the computer type that we need to build. For example, A laptop users can choose touch screen and the desktop users can configure keyboard and mouse.
Here are the steps to implement builder design pattern :
Step 1 : Add ISystemBuilder interface
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Web.Builder.IBuilder { public interface ISystemBuilder { void AddMemory(string memory); void AddDrive(string size); void AddKeyBoard(string type); void AddMouse(string type); void AddTouchScreen(string enabled); ComputerSystem GetSystem(); } }
Step 2 : Add desktop builder and inherit ISystemBuilder interface and implement the Interface methods and assign the properties to the computer system that is being built.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Web.Builder.IBuilder; namespace Web.Builder.ConcreteBuilder { public class DesktopBuilder : ISystemBuilder { ComputerSystem desktop = new ComputerSystem(); public void AddDrive(string size) { desktop.HDDSize = size; } public void AddKeyBoard(string type) { desktop.KeyBoard = type; } public void AddMemory(string memory) { desktop.RAM = memory; } public void AddMouse(string type) { desktop.Mouse = type; } public void AddTouchScreen(string enabled) { return; } public ComputerSystem GetSystem() { return desktop; } } }
Step 3 : Add laptop builder and inherit ISystemBuilder interface and implement the Interface methods and assign the properties to the computer system that is being built.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using Web.Builder.IBuilder; namespace Web.Builder.ConcreteBuilder { public class LaptopBuilder : ISystemBuilder { ComputerSystem laptop = new ComputerSystem(); public void AddDrive(string size) { laptop.HDDSize = size; } public void AddKeyBoard(string type) { return; } public void AddMemory(string memory) { laptop.RAM = memory; } public void AddMouse(string type) { return; } public void AddTouchScreen(string enabled) { laptop.TouchScreen = enabled; } public ComputerSystem GetSystem() { return laptop; } } }
Step 4 : Add configuration builder class which is the director to build the system
using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; using System.Web; using Web.Builder.IBuilder; namespace Web.Builder.Director { public class ConfigurationBuilder { public void BuildSystem(ISystemBuilder systembuilder , NameValueCollection collection) { systembuilder.AddDrive(collection["Drive"]); systembuilder.AddMemory(collection["RAM"]); systembuilder.AddMouse(collection["Mouse"]); systembuilder.AddKeyBoard(collection["Keyboard"]); systembuilder.AddTouchScreen(collection["TouchScreen"]); } } }
Step 5 : Remove the constructor with the parameters and change the private properties to public so that they can be initialized from the concrete builder classes
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace Web { public class ComputerSystem { public string RAM { get; set; } public string HDDSize { get; set; } public string KeyBoard { get; set; } public string Mouse { get; set; } public string TouchScreen { get; set; } public ComputerSystem() { } } }
Step 6 : Enhance the BuildSystem action method from the previous session by returning desktop and laptop views based on the system allocated to the employees
[HttpGet] public ActionResult BuildSystem(int? employeeID) { Employee employee = db.Employees.Find(employeeID); if (employee.ComputerDetails.Contains("Laptop")) return View("BuildLaptop", employeeID); else return View("BuildDesktop", employeeID); }
Step 7 : Add Build laptop action method as shown below
[HttpPost] public ActionResult BuildLaptop(FormCollection formCollection) { Employee employee = db.Employees.Find(Convert.ToInt32(formCollection["employeeID"])); //Concrete Builder ISystemBuilder systemBuilder = new LaptopBuilder(); //Director ConfigurationBuilder builder = new ConfigurationBuilder(); builder.BuildSystem(systemBuilder, formCollection); ComputerSystem system= systemBuilder.GetSystem(); employee.SystemConfigurationDetails = string.Format("RAM : {0}, HDDSize : {1}, TouchScreen: {2}" , system.RAM, system.HDDSize, system.TouchScreen); db.Entry(employee).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); }
Step 8 : Add build desktop action method as shown below
[HttpPost] public ActionResult BuildDesktop(FormCollection formCollection) { //Step 1 Employee employee = db.Employees.Find(Convert.ToInt32(formCollection["employeeID"])); //Step 2 Concrete Builder ISystemBuilder systemBuilder = new DesktopBuilder(); //Step 3 Director ConfigurationBuilder builder = new ConfigurationBuilder(); builder.BuildSystem(systemBuilder, formCollection); //Step 4 return the system ComputerSystem system = systemBuilder.GetSystem(); employee.SystemConfigurationDetails = string.Format("RAM : {0}, HDDSize : {1}, Keyboard: {2}, Mouse : {3}" , system.RAM, system.HDDSize, system.KeyBoard, system.Mouse); db.Entry(employee).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index");}
Step 9 : Create Desktop and Laptop views as shown below. On submit post the details to the respective action methods built in step 7 and step 8
@model Int32 @{ ViewBag.Title = "BuildSystem"; }
<h2>Build System</h2>
<style>
input[type=radio] {
border: 0px;
width: 100%;
height: 1em;
}
</style>
@using (Html.BeginForm("BuildDesktop", "Employees", FormMethod.Post ))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>
System
Configuration
</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.Hidden("employeeID", this.Model.ToString());
<div class="form-group">
@Html.Label("Memory", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("RAM",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "8GB", Value="8GB"},
new SelectListItem (){ Text = "16GB", Value="16GB"},
new SelectListItem (){ Text = "32GB", Value="32GB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.Label("Drive", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("Drive",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "500GB", Value="500GB"},
new SelectListItem (){ Text = "1TB", Value="1TB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.Label("Mouse", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("Mouse",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "WireLess", Value="USB-WireLess"},
new SelectListItem (){ Text = "Regular-USB", Value="USB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.Label("KeyBoard", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("KeyBoard",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "Wireless", Value="Wireless"},
new SelectListItem (){ Text = "Regular-USB", Value="Regular-USB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class
="btn
btn-default"
/>
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
@model span >< span lang = "EN-US" style = "color: #2b91af;" > Int32 span >< span lang = "EN-US" >< o:p > o:p > span > span > div >
@{
ViewBag.Title = "BuildSystem";
}
<h2>Build System</h2>
<style>
input[type=radio] {
border: 0px;
width: 100%;
height: 1em;
}
</style>
@using (Html.BeginForm("BuildLaptop", "Employees", FormMethod.Post))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>System Configuration</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.Hidden("employeeID", this.Model.ToString());
<div class="form-group">
@Html.Label("Memory", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("RAM",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "8GB", Value="8GB"},
new SelectListItem (){ Text = "16GB", Value="16GB"},
new SelectListItem (){ Text = "32GB", Value="32GB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.Label("Drive", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
@Html.DropDownList("Drive",
new List<SelectListItem>() {
new SelectListItem (){ Text = "Select", Value="Select"},
new SelectListItem (){ Text = "500GB", Value="500GB"},
new SelectListItem (){ Text = "1TB", Value="1TB"},
},
htmlAttributes:
new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.Label("Touch Enbled", htmlAttributes: new { @class =
"control-label
col-md-2"
})
<div class="col-md-10">
<div class="col-md-1">
<label>@Html.RadioButton("TouchScreen", "Yes", false, htmlAttributes: new { @class = "radio-inline" }) YES</label>
</div>
<div class="col-md-1">
<label>@Html.RadioButton("TouchScreen", "NO", false, htmlAttributes: new { @class = "radio-inline" }) NO</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class
="btn
btn-default"
/>
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
Step 11 : With this we have successfully addressed requirement by using the builder design pattern