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

.NET 設計模式實戰:策略模式讓 List 排序靈活多變,告別硬編碼比較邏輯

     編輯:ASP.NET 基礎

問題場景:List 排序的演進之路

第一階段:簡單型別直接 Sort()


var numbers = new List { 5, 2, 9, 1 };
numbers.Sort(); // 內建支援 IComparable

第二階段:實作 IComparable 的類別


public class Student : IComparable
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int Score { get; set; }

    public int CompareTo(Student other) => this.Score.CompareTo(other.Score); // 固定按分數排
}

缺點:比較邏輯寫死在類別內,無法依情境切換(有時按名字、有時按分數、有時按 ID)。

第三階段:IComparer 外部比較器


public class StudentScoreComparer : IComparer
{
    public int Compare(Student x, Student y) => x.Score.CompareTo(y.Score);
}

students.Sort(new StudentScoreComparer()); // 靈活指定比較策略

這就是 策略模式 的雛形:將演算法(比較邏輯)封裝成可互換的策略物件。

策略模式結構圖解

+----------------+          +---------------------+
|   Context      |<>------->|   Strategy (介面)   |
|  (ListSorter)  |          |  + Compare(T, T)    |
+----------------+          +---------------------+
                                    ^           ^
                                    |           |
                    +---------------+           +---------------+
                    |                                   |
            +-------------------+               +-------------------+
            | ConcreteStrategyA |               | ConcreteStrategyB |
            |  (ScoreComparer)  |               |  (NameComparer)   |
            +-------------------+               +-------------------+

三大角色

  1. Strategy (抽象策略):定義演算法介面,如 `IComparer` 或自訂 `IComparer_sly`
  2. ConcreteStrategy (具體策略):實作不同演算法,如 `ScoreAscComparer`、`NameDescComparer`
  3. Context (環境角色):持有策略引用,委派執行,如 `ListSorter`

從零手刻通用 List 排序框架

1. 定義策略介面


public interface IComparer_sly
{
    int Compare(T x, T y);
}

2. 環境角色:封裝快速排序演算法


public class ListSorter
{
    private List _list = new List();
    public List Items => _list;

    public void Add(T item) => _list.Add(item);
    public void AddRange(IEnumerable items) => _list.AddRange(items);

    // 核心:接受策略介面,執行排序
    public void Sort(IComparer_sly comparer)
    {
        T[] array = _list.ToArray();
        QuickSort(array, 0, array.Length - 1, comparer);
        _list = new List(array);
    }

    private void QuickSort(T[] array, int left, int right, IComparer_sly comparer)
    {
        if (left >= right) return;
        T pivot = array[(left + right) / 2];
        int i = left - 1, j = right + 1;
        while (true)
        {
            while (comparer.Compare(array[++i], pivot) < 0) ;
            while (comparer.Compare(array[--j], pivot) > 0) ;
            if (i >= j) break;
            (array[i], array[j]) = (array[j], array[i]); // C# 7+ tuple swap
        }
        QuickSort(array, left, i - 1, comparer);
        QuickSort(array, j + 1, right, comparer);
    }
}

3. 具體策略:支援多欄位、升降冪切換


public class StudentComparer : IComparer_sly
{
    private readonly string _field;      // "id" | "name" | "score"
    private readonly bool _ascending;    // true=升冪, false=降冪

    public StudentComparer(string field, bool ascending)
    {
        _field = field.ToLower();
        _ascending = ascending;
    }

    public int Compare(Student x, Student y)
    {
        object v1 = GetValue(x), v2 = GetValue(y);
        int result = Comparer.Default.Compare(v1, v2); // 處理 null、字串、數值
        return _ascending ? result : -result;
    }

    private object GetValue(Student s) => _field switch
    {
        "id" => s.Id,
        "name" => s.Name,
        "score" => s.Score,
        _ => null
    };
}

4. 客戶端使用:一行切換排序規則


var sorter = new ListSorter();
for (int i = 0; i < 10; i++)
    sorter.Add(new Student(i, $"Student_{9-i}", 100 - i * 5));

Console.WriteLine("原始順序:");
sorter.Items.ForEach(s => Console.WriteLine($"{s.Id} {s.Name} {s.Score}"));

// 按姓名升冪
sorter.Sort(new StudentComparer("name", true));
Console.WriteLine("\n姓名升冪:");
sorter.Items.ForEach(s => Console.WriteLine($"{s.Id} {s.Name} {s.Score}"));

// 按分數降冪
sorter.Sort(new StudentComparer("score", false));
Console.WriteLine("\n分數降冪:");
sorter.Items.ForEach(s => Console.WriteLine($"{s.Id} {s.Name} {s.Score}"));

.NET 內建 List.Sort() 如何運作?

反編譯可見:`List.Sort()` → `Array.Sort(_items, 0, Count, comparer)` → `ArraySortHelper.Default.Sort()` → 內部為 內省排序(Introspective Sort:快速排序 + 堆積排序 + 插入排序混合),並大量進行邊界檢查與例外處理。我們手刻的快速排序僅為教學示範,生產環境請直接使用內建 `List.Sort(IComparer)`。

策略模式適用場景

  • 同一行為有多種演算法實現(排序、壓縮、加密、路由、計價)
  • 需在執行時動態切換演算法
  • 想避免大量 `if/else` 或 `switch` 判斷演算法類型
  • 演算法邏輯頻繁變動或擴充,不想修改 Context 核心代碼

優缺點總結

優點缺點
符合開放封閉原則:新增策略不修改既有代碼策略類別數量增加,維護成本略增
消除條件判斷,程式碼更乾淨客戶端需知曉所有具體策略類別
演算法可獨立單元測試簡單場景引入策略模式屬於過度設計
支援執行時熱插拔演算法

總結

策略模式將 「什麼時候排序」與「怎麼比較大小」解耦,讓 `ListSorter` 專注於排序演算法本身,而比較規則由外部注入。這正是「針對介面編程、封裝變化」的經典實踐。下次面對多重排序需求時,請優先考慮 `IComparer` + 策略模式,而非在實體類別塞滿 `if (sortBy == "name")`。

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