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

C# 設計模式:模板方法模式 定義演算法骨架,延遲細節到子類別

     編輯:關於C語言

生活類比:簡歷模板

大家下載同一份「簡歷模板」(骨架:姓名、學歷、經歷、技能),但每個人填入的內容(細節)完全不同。模板方法模式正是將不變的流程固定在父類別,將變化的步驟交給子類別實作。

模式定義

在抽象類別中定義演算法的骨架,將某些步驟延遲到子類別實作。模板方法讓子類別不改變演算法結構前提下,重新定義特定步驟。

類別結構

模板方法模式結構圖

  • AbstractClass:定義模板方法、抽象基本步驟、可選鉤子方法
  • ConcreteClass:實作抽象步驟、可覆寫鉤子方法

核心守則:好萊塢原則

「別呼叫我們,我們會呼叫你」 —— 父類別呼叫子類別方法,而非反向。

  • 模板方法標記 sealed(或非 virtual)防止被覆寫
  • 基本步驟標記 protected abstract 強制子類實作
  • 鉤子方法標記 protected virtual 提供預設行為,子類選擇性覆寫

完整實作:薪資計算系統

1. 抽象父類別


public abstract class SalaryCalculator
{
    // === 模板方法:定義演算法骨架 ===
    public sealed decimal CalculateNetSalary(Employee emp)
    {
        decimal basic = CalculateBasicSalary(emp);      // 步驟 1:基本薪資
        decimal bonus = CalculateBonus(emp);            // 步驟 2:獎金
        decimal allowance = CalculateAllowance(emp);    // 步驟 3:津貼
        decimal gross = basic + bonus + allowance;      // 步驟 4:應發薪資
        decimal tax = CalculateTax(gross, emp);         // 步驟 5:扣稅
        decimal insurance = CalculateInsurance(gross);  // 步驟 6:保險
        return gross - tax - insurance;                 // 步驟 7:實發薪資
    }

    // === 抽象基本步驟:子類別必須實作 ===
    protected abstract decimal CalculateBasicSalary(Employee emp);
    protected abstract decimal CalculateBonus(Employee emp);

    // === 鉤子方法:提供預設實作,子類別可選擇覆寫 ===
    protected virtual decimal CalculateAllowance(Employee emp) => 0m; // 預設無津貼
    protected virtual decimal CalculateTax(decimal gross, Employee emp) => gross * 0.05m; // 預設 5%
    protected virtual decimal CalculateInsurance(decimal gross) => gross * 0.02m; // 預設 2%
}

2. 具體子類別:經理


public class ManagerSalaryCalculator : SalaryCalculator
{
    protected override decimal CalculateBasicSalary(Employee emp) => 80000m;

    protected override decimal CalculateBonus(Employee emp) 
        => emp.PerformanceRating switch
        {
            "A" => 30000m,
            "B" => 20000m,
            _ => 10000m
        };

    protected override decimal CalculateAllowance(Employee emp) => 10000m; // 職務津貼
}

3. 具體子類別:CEO


public class CeoSalaryCalculator : SalaryCalculator
{
    protected override decimal CalculateBasicSalary(Employee emp) => 200000m;

    protected override decimal CalculateBonus(Employee emp) => emp.CompanyProfit * 0.01m; // 分紅

    protected override decimal CalculateTax(decimal gross, Employee emp) 
        => gross * 0.20m; // 高階主管稅率不同

    protected override decimal CalculateInsurance(decimal gross) 
        => 30000m; // 上限封頂
}

4. 客戶端使用


class Program
{
    static void Main()
    {
        var empManager = new Employee { Id = 1, Name = "王經理", PerformanceRating = "A" };
        var empCeo = new Employee { Id = 2, Name = "趙總", CompanyProfit = 50000000m };

        var mgrCalc = new ManagerSalaryCalculator();
        var ceoCalc = new CeoSalaryCalculator();

        Console.WriteLine($"經理實發薪資: {mgrCalc.CalculateNetSalary(empManager):C}");
        Console.WriteLine($"CEO 實發薪資: {ceoCalc.CalculateNetSalary(empCeo):C}");
        Console.ReadKey();
    }
}

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string PerformanceRating { get; set; }
    public decimal CompanyProfit { get; set; }
}

.NET 框架中的模板方法實例

類別/方法模板方法可覆寫步驟
WebForms PageProcessRequestOnInit, OnLoad, OnPreRender, Render
ASP.NET Core ControllerExecuteCoreAsyncOnActionExecuting, OnActionExecuted, OnResultExecuting
StreamRead, WriteReadByte, WriteByte
Entity Framework DbContextSaveChangesOnConfiguring, OnModelCreating, SaveChangesAsync

優缺點權衡

優點缺點
✅ 程式碼複用(共同流程集中)
✅ 反轉控制(父呼叫子)
✅ 符合開閉原則(擴充子類別不修改父類)
✅ 統一演算法結構,降低邏輯錯誤
⚠️ 類別數量增加(每個變體一個子類)
⚠️ 繼承耦合度較高
⚠️ 步驟過多時模板方法過長,難以維護

適用場景

  • 多個子類別擁有相同演算法結構,僅細節不同
  • 重要、複雜演算法,核心流程需固定,細節開放擴充
  • 重構時將重複程式碼上移至父類別
  • 框架設計:定義流程骨架,使用者填入業務邏輯

結語

模板方法模式是繼承複用的經典應用。關鍵在於:識別什麼是不變的(骨架),什麼是變化的(步驟)。善用 sealed 保護模板方法、abstract 強制實作、virtual 提供彈性,即可建立穩固且可擴充的演算法框架。

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