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

C# 替換 Switch 的五種模式:工廠、字典、策略、多態與模式匹配

     編輯:ASP.NET 基礎

為什麼要替換 Switch?

  • 開閉原則違背:新增分支需修改原方法,違反「對擴展開放,對修改關閉」。
  • 單一職責缺失:巨大 Switch 混雜多種業務邏輯,難以單元測試。
  • 擴展性差:插件化、動態載入場景無法靜態編譯所有分支。

場景假設

根據字符串 methodName 執行不同邏輯,返回字符串結果。

模式一:工廠模式 + 介面(經典 OOP)

// 1. 介面
public interface IMethodHandler
{
    string Execute();
}

// 2. 具體實現
public class GetHandler : IMethodHandler
{
    public string Execute() => "get";
}
public class GetTestHandler : IMethodHandler
{
    public string Execute() => "gettest";
}
public class GetSetHandler : IMethodHandler
{
    public string Execute() => "getset";
}

// 3. 工廠(可擴展為字典/反射/自動註冊)
public static class MethodFactory
{
    private static readonly Dictionary> _map = new(StringComparer.OrdinalIgnoreCase)
    {
        ["get"] = () => new GetHandler(),
        ["gettest"] = () => new GetTestHandler(),
        ["getset"] = () => new GetSetHandler(),
    };

    public static IMethodHandler Create(string name)
    {
        if (_map.TryGetValue(name, out var factory))
            return factory();
        throw new ArgumentException($"Unknown method: {name}");
    }
}

// 4. 調用
public string Exec(string methodName)
{
    var handler = MethodFactory.Create(methodName);
    return handler.Execute();
}

模式二:字典委託(輕量、函數式)

private static readonly Dictionary> _actions = new(StringComparer.OrdinalIgnoreCase)
{
    ["get"] = () => "get",
    ["gettest"] = () => "gettest",
    ["getset"] = () => "getset",
};

public string Exec(string methodName)
{
    return _actions.TryGetValue(methodName, out var action) ? action() : throw new ArgumentException($"Unknown: {methodName}");
}

模式三:策略模式(邏輯複雜、有狀態)

public interface IStrategy
{
    string Name { get; }
    string Execute(Context ctx);
}

public class GetStrategy : IStrategy
{
    public string Name => "get";
    public string Execute(Context ctx) => "get"; // 可訪問 ctx 共享數據
}

public class StrategyContext
{
    private readonly IEnumerable _strategies;
    public StrategyContext(IEnumerable strategies) => _strategies = strategies;

    public string Execute(string name, Context ctx)
    {
        var strategy = _strategies.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
        return strategy?.Execute(ctx) ?? throw new ArgumentException($"No strategy: {name}");
    }
}

// DI 註冊:services.AddTransient(); 等
// 控制器構造注入 StrategyContext

模式四:多態分發(領域模型核心)

public abstract class MethodBase
{
    public abstract string Name { get; }
    public abstract string Execute();
}

public class GetMethod : MethodBase
{
    public override string Name => "get";
    public override string Execute() => "get";
}

// 使用:List methods = ...; 
// methods.First(m => m.Name == name).Execute();

模式五:C# 8+ Switch Expression / Pattern Matching(語法糖,保留 Switch 但優雅)

public string Exec(string methodName) => methodName.ToLowerInvariant() switch
{
    "get" => "get",
    "gettest" => "gettest",
    "getset" => "getset",
    _ => throw new ArgumentException($"Unknown: {methodName}")
};

// 類型模式匹配
public string Process(object input) => input switch
{
    int i => $"Int: {i}",
    string s => $"String: {s}",
    DateTime dt => $"Date: {dt:yyyy-MM-dd}",
    null => "Null",
    _ => "Other"
};

// 屬性模式
public string Describe(User u) => u switch
{
    { Role: "Admin", IsActive: true } => "Active Admin",
    { Role: "User", LastLogin: var login } when login > DateTime.Now.AddDays(-30) => "Active User",
    _ => "Guest"
};

反射動態創建(插件/配置驅動)

public static IMethodHandler CreateByReflection(string name)
{
    // 約定:命名空間 + 名稱 + "Handler",程序集名
    string typeName = $"MyApp.Handlers.{name.FirstCharToUpper()}Handler";
    var type = Type.GetType(typeName) ?? Assembly.Load("MyApp.Handlers").GetType(typeName);
    return (IMethodHandler)Activator.CreateInstance(type);
}

// 擴展方法
public static string FirstCharToUpper(this string s) => 
    string.IsNullOrEmpty(s) ? s : char.ToUpper(s[0]) + s[1..];

選型指南

場景推薦模式理由
簡單映射、無狀態、高性能字典委託O(1) 查找、零分配、極簡
邏輯複雜、需依賴注入、可測試策略模式 + DI單一職責、易 Mock、生命週期可控
插件系統、動態載入、配置驅動反射/工廠 + 約定運行時發現、無需重新編譯宿主
領域建模、行為與數據封裝多態豐富領域模型、消除基元類型癡迷
少量分支、代碼局部、追求簡潔Switch Expression語法簡潔、編譯器優化、可擴展模式匹配

反模式警示

  • ❌ 用 if-else 鏈代替 Switch —— 同樣違反 OCP,可讀性更差。
  • ❌ 在字典值中存儲 Type 每次 Activator.CreateInstance —— 性能差,應緩存工廠委託 Func。
  • ❌ 將所有邏輯塞進一個巨大的 Execute 方法 —— 退化為「上帝類」。

掌握這五種模式,即可在代碼審查中自信地重構「巨大 Switch」,讓業務邏輯清晰、可測、可擴展。

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