首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 設計模式:建造者模式 將複雜物件建構與表示分離

     編輯:關於C語言

問題背景

建構一個「學生選課成績單」物件,包含:必修、選修、限修三類課程,每類課程又有不同科目與學分。若用建構函數,參數過多、順序易搞錯、難以擴充;若用屬性逐一設定,可能產生「半初始化」的無效物件。建造者模式透過分步驟建構、指導者控制流程、建造者封裝細節,優雅解決此類問題。

模式定義

將一個複雜物件的建構與它的表示分離,使得相同的建構過程可以創建不同的表示。

類別結構

建造者模式結構圖

  • Product:複雜物件(課程成績單)
  • Builder:抽象建造介面(定義建構步驟)
  • ConcreteBuilder:具體建造者(大學部/研究所不同規則)
  • Director:指導者(控制建構順序)

完整實作:學生選課成績單系統

1. 產品類別


public class CourseReport
{
    private readonly Dictionary _courses = new();

    public void AddCourse(string courseId, decimal score)
    {
        _courses[courseId] = score;
    }

    public decimal CalculateTotalScore()
    {
        decimal total = 0;
        foreach (var kvp in _courses)
        {
            Console.WriteLine($"課程:{kvp.Key} 成績:{kvp.Value}");
            total += kvp.Value;
        }
        return total;
    }
}

2. 抽象建造者


public abstract class CourseReportBuilder
{
    protected CourseReport _report = new();

    // 固定建構步驟(演算法骨架)
    public abstract void BuildRequiredCourses();   // 必修
    public abstract void BuildElectiveCourses();   // 選修
    public abstract void BuildRestrictedCourses(); // 限修

    public CourseReport GetReport() => _report;
}

3. 具體建造者:大學部


public class UndergraduateBuilder : CourseReportBuilder
{
    public override void BuildRequiredCourses()
    {
        _report.AddCourse("UG-101", 80m); // 微積分
        _report.AddCourse("UG-102", 85m); // 物理
    }

    public override void BuildElectiveCourses()
    {
        _report.AddCourse("UG-E01", 90m); // 程式設計入門
    }

    public override void BuildRestrictedCourses()
    {
        _report.AddCourse("UG-R01", 95m); // 體育(必選)
    }
}

4. 具體建造者:研究所


public class GraduateBuilder : CourseReportBuilder
{
    public override void BuildRequiredCourses()
    {
        _report.AddCourse("GR-501", 70m); // 進階演算法
        _report.AddCourse("GR-502", 75m); // 機器學習理論
    }

    public override void BuildElectiveCourses()
    {
        _report.AddCourse("GR-E01", 80m); // 深度學習實務
    }

    public override void BuildRestrictedCourses()
    {
        _report.AddCourse("GR-R01", 85m); // 學術倫理
    }
}

5. 指導者


public class ReportDirector
{
    // 控制建構順序(不可變)
    public void Construct(CourseReportBuilder builder)
    {
        builder.BuildRequiredCourses();
        builder.BuildElectiveCourses();
        builder.BuildRestrictedCourses();
    }
}

6. 客戶端使用


class Program
{
    static void Main()
    {
        var director = new ReportDirector();

        // 建構大學部成績單
        var ugBuilder = new UndergraduateBuilder();
        director.Construct(ugBuilder);
        var ugReport = ugBuilder.GetReport();
        Console.WriteLine($"=== 大學部總分: {ugReport.CalculateTotalScore()} ===\n");

        // 建構研究所成績單
        var grBuilder = new GraduateBuilder();
        director.Construct(grBuilder);
        var grReport = grBuilder.GetReport();
        Console.WriteLine($"=== 研究所總分: {grReport.CalculateTotalScore()} ===");

        Console.ReadKey();
    }
}

執行結果


=== 大學部總分: 350 ===
課程:UG-101 成績:80
課程:UG-102 成績:85
課程:UG-E01 成績:90
課程:UG-R01 成績:95

=== 研究所總分: 310 ===
課程:GR-501 成績:70
課程:GR-502 成績:75
課程:GR-E01 成績:80
課程:GR-R01 成績:85

進階:流暢介面建造者

現代 C# 常用鏈式呼叫取代 Director,更直覺:


public class FluentCourseReportBuilder
{
    private readonly CourseReport _report = new();

    public FluentCourseReportBuilder AddRequired(string id, decimal score)
    {
        _report.AddCourse($"REQ-{id}", score);
        return this;
    }

    public FluentCourseReportBuilder AddElective(string id, decimal score)
    {
        _report.AddCourse($"ELE-{id}", score);
        return this;
    }

    public CourseReport Build() => _report;
}

// 使用
var report = new FluentCourseReportBuilder()
    .AddRequired("Math", 90)
    .AddRequired("Physics", 85)
    .AddElective("CSharp", 95)
    .Build();

建造者模式 vs 工廠模式 vs 模板方法

模式核心意圖關鍵差異
建造者分步驟建構複雜物件強調建構過程、可產生不同表示
工廠方法建立單一物件一次建立完成、無建構步驟
抽象工廠建立相關物件家族多個產品、無建構順序
模板方法定義演算法骨架行為導向、非物件建構

優缺點與適用場景

優點缺點
✅ 封裝建構細節,使用者只需指定型別
✅ 可精確控制建構順序
✅ 易於新增新的建造者(開閉原則)
✅ 避免超長建構函數/屬性初始化器
⚠️ 類別數量增加
⚠️ 產品內部結構變動時,所有建造者需同步修改
⚠️ 簡單物件使用過度設計

✅ 適用場景

  • 物件包含多個組成部分,且建構步驟固定但細節多變
  • 需要產生不同表示(如匯出 PDF/Excel/HTML 報表)
  • 建構過程需依賴外部資源(資料庫、API、檔案)
  • 不可變物件建構(建構完成後凍結狀態)

結語

建造者模式以「分步驟、可控制、可擴充」的方式,解決複雜物件建構的痛點。現代 C# 開發中,流暢介面與不可變物件風格更受青睞,但核心思想不變:將「如何建構」與「建構什麼」分離。下次面對參數超過 5 個的建構函數,請考慮引入 Builder。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved