專案中需要在MVC同一個VIEW上動態依照後端提供的每種產品規格(View Model)做隱藏/顯示欄位(選項)。
本範例將使用建造者模式(Builder)來達到此目的。
我們先抓出這個需求相對複雜的地方:
建造者模式(Builder)可以在不需要知道細節的情況下建立一個完整的物件,並隨時抽換細節。
所以我們採用建造者模式來完成這個需求。
程式碼用比較好舉例的方式撰寫。 假設我們要成立一個小家庭(產品),而每個小家庭有不同的規格(父母、小孩、寵物...etc)。
在產出一筆小家庭的資料時,我們利用建造者模式來逐步建立"父母"、"小孩"、"寵物"的資料。
dotnet new mvc --name DP.Website
dotnet sln DP.sln add DP.Website/DP.Website.csproj
cd DP.Website
dotnet restore
dotnet build  
public class Home
{
    public string Address { get; set; }
    public List<Parent> Parents { get; set; }
    public List<Child> Children { get; set; }
    public List<Pet> Pets { get; set; }
}
public class Parent
{
    public string Id { get; set; }
    [DisplayName("父母姓名")]
    public string Name { get; set; }
}
public class Child
{
    public string Id { get; set; }
    [DisplayName("小孩姓名")]
    public string Name {get;set;}
    [DisplayName("生日")]
    public string Birthday { get; set; }
}
public class Pet
{
    public string Id { get; set; }
    [DisplayName("名字")] 
    public string Name { get; set; }
    [DisplayName("寵物")]
    public string PetType { get; set; }
}
有了ViewModel,我們先不管怎麼塞資料,先加上一個Action如下。
public IActionResult Builder()
{
    Home viewModel = new Home();
    return View(viewModel);
}
再分別建立對應的View和Partial Views
@model DP.Website.Models.Parent
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
    </tr>
    @if (Model != null)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => Model.Name)
            </td>
        </tr>
    }
</table>
小孩(_ChildPartial.cshtml)和寵物的部分可以參考連結,就不佔篇幅。
接下來建立主要的View:
@model DP.Website.Models.Home
<div style="background-color:lightblue">
    @if (Model.Parents != null)
    {
        for (int i = 0; i < Model.Parents.Count(); i++)
        {
            @Html.Partial("_ParentPartial", Model.Parents.ToList()[i])
        }
    }
</div>
<div style="background-color:lightcyan">
    @if (Model.Children != null)
    {
        for (int i = 0; i < Model.Children.Count(); i++)
        {
            @Html.Partial("_ChildPartial", Model.Children.ToList()[i])
        }
    }
</div>
<div style="background-color:lightgreen">
    @if (Model.Pets != null)
    {
        for (int i = 0; i < Model.Pets.Count(); i++)
        {
            @Html.Partial("_PetPartial", Model.Pets.ToList()[i])
        }
    }
</div>
有了View和Controller,我們下面開始實作用建造者模式塞資料到View Model物件裡面。
public abstract class Builder
{
        /// 建立物件
    abstract public Home Init();
    abstract public void BuildParent(Home home);
    abstract public void BuildChild(Home home);
    abstract public void BuildPet(Home home);
}
讓Director來負責處理"如何建造"。
public class Director
{
    private Builder _builder;
    public Director(Builder builder)
    {
        this._builder = builder;
    }
    public Home Construct()
    {
        var home = this._builder.Init();
        this._builder.BuildParent(home);
        this._builder.BuildChild(home);
        this._builder.BuildPet(home);
        return home;
    }
}
現在我們可以專心實作"建造"的細節。
假設我們需要建造兩個不同的星際大戰小家庭:
所以我們建立兩個ConcreteBuilder如下:
public class Builder4Skywlker : Builder
{
    public override Home Init()
    {
        return new Home
        {
            Address = "Naboo"
        };
    }
    public override void BuildParent(Home home)
    {
        home.Parents = new List<Parent>{
            new Parent() { Name = "Anakin Skywalker"},
            new Parent() { Name = "Princess Amidala"},
        };
    }
    public override void BuildChild(Home home)
    {
        home.Children = new List<Child>{
            new Child(){Name="Luke Skywalker", Birthday="2099/5/4"},
            new Child(){Name="Luke Skywalker", Birthday="2099/5/4"}
        };
    }
    public override void BuildPet(Home home)
    {
        home.Pets = new List<Pet>{
            new Pet(){Name="Jar Jar Binks", PetType="Gungan"}    
        };
    }
}
public class Builder4Solo : Builder
{
    public override Home Init()
    {
        return new Home
        {
            Address = "Milian falcon"
        };
    }
    public override void BuildParent(Home home)
    {
        home.Parents = new List<Parent>{
            new Parent() { Name = "Han Solo"},
            new Parent() { Name = "Leia Skywalker"},
        };
    }
    public override void BuildChild(Home home)
    {
        home.Children = new List<Child>{
            new Child(){Name="Ben Solo", Birthday="2123/5/4"}
        };
    }
    public override void BuildPet(Home home)
    { 
        //Not a good idea of putting Chewbacca here...
    }
}
由上面程式碼可以看到Builder4Solo(索羅家庭)並沒有寵物(如果以產品來看,就是不提供這個規格)。
最後我們回到Controller,並把建造者模式更新到產生View Model的程式碼:
public IActionResult Builder()
{
    Builder builder = new Builder4Skywlker();
    var director = new Director(builder);
    //Build it!
    Home viewModel = director.Construct();
    return View(viewModel);
}
執行畫面如下:

當我們抽換ConcreteBuilder時:Builder builder = new Builder4Solo();
