熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

應用策略模式為List排序

2013-11-13 10:00:00  來源: .NET編程 

  編程時遇到排序在平常不過使用Net最常見的就是對泛型List<T>進行排序如果T是簡單數據類型排序那麼很簡單直接調用List的Sort()方法就可以了但是如果我們要排的對象復雜了怎麼辦我們知道List<T> sort()最後是用快速排序實現快速排序也好什麼排序都需要知道list中item之間的比較結果如果是簡單的int類型直接判斷即可對實現了IComparable接口的對象可以調用其CompareTo()實現item比較大小下面是一個快速排序的寫法

  void Sort<T>(T[] array int left int right IComparer_sly<T> comparer) where T : IComparable
        {
            if (left < right)
            {
                T middle = array[(left + right) / ];
                int i = left ;
                int j = right + ;
                while (true)
                {
                    while (array[++i]CompareTo(middle) < ) ;

  while (array[j]CompareTo(middle) > ) ;

  if (i >= j)
                        break;

  T temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }

  Sort(array left i comparer);
                Sort(array j + right comparer);
            }
        }

  問題

  對於前兩種情況固然可以實現排序但是我們不可能要求所有待排序的對象都實現IComparable接口就算能夠保證每個對象都實現IComparable接口如果想實現對象內多個字段排序比如Student對象有時候想按照姓名排序有時候是成績有時候是年齡這怎麼破

  按照面向對象的思想要把變化獨立出來封裝變化對於我們排序List<T>時變化的其實就是怎麼比較兩個對象的大小的算法如果我們可以把這個算法拿出來排序就簡單了很多無論什麼排序算法都是由的我們要封裝的部分是怎樣比較兩個item的大小的算法為了實現拓展性我們要遵循面向對象設計的另外一個重要原則針對接口編程而不是針對實現編程

  編寫通用的List<T>排序方法首先定義一個接口裡面有一個比較item大小的方法在排序的時候作為參數傳入當然是傳入它的實現類有了這個想法我們可以自己寫個List<T>的排序方法

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

  然後為了測試我們為List<T>加一個包裝寫一個自己的Sort方法內部也用快速排序實現一直困惑我們的變化部分——比較大小算法我們把它封轉起來作為參數傳入

  using System;
using SystemCollectionsGeneric;

  namespace TestStategy
{public class ListTest<T>
    {
        public List<T> list = new List<T>();
        public void Sort(IComparer_sly<T> comparer)
        {
            T[] array = listToArray();
            int left = ;
            int right = arrayLength ;
            QuickSort(array left right comparer);
            list = new List<T>(array);
        }

  private void QuickSort<S>(S[] array int left int right IComparer_sly<S> comparer)
        {
            if (left < right)
            {
                S middle = array[(left + right) / ];
                int i = left ;
                int j = right + ;
                while (true)
                {
                    while (comparerCompare(array[++i] middle) < ) ;

  while (comparerCompare(array[j] middle) > ) ;

  if (i >= j)
                        break;

  S temp = array[i];
                    array[i] = array[j];
                    array[j] = temp;
                }

  QuickSort(array left i comparer);
                QuickSort(array j + right comparer);
            }
        }
    }
}比如現在我們有個Student 的實體

  public class Student
    {
        public Student(int id string name)
        {
            thisID = id;
            thisName = name;
        }
        public int ID { get; set; }
        public string Name { get; set; }
    }

  如果想對這個實體組成的List<T>進行排序我們只需一個實現 IComparer_sly<Student>的類 StudentComparer並在內部實現其比較大小方法——Compare()同時我們可以添加遞增還是遞減排序的控制

  class StudentComparer : IComparer_sly<Student>
    {
        private string expression;
        private bool isAscending;
        public StudentComparer(string expression bool isAscending)
        {
            thisexpression = expression;
            thisisAscending = isAscending;
        }

  public int Compare(Student x Student y)
        {
            object v = GetValue(x) v = GetValue(y);
            if (v is string || v is string)
            {
                string s = ((v == null) ? : vToString()Trim());
                string s = ((v == null) ? : vToString()Trim());
                if (sLength == && sLength == )
                    return ;
                else if (sLength == )
                    return ;
                else if (sLength == )
                    return ;
            }

  // 這裡就偷懶調用系統方法不自己實現了其實就是比較兩個任意相同類型數據大小自己實現比較麻煩
            if (!isAscending)
                return ComparerDefaultCompare(v v);
            return ComparerDefaultCompare(v v);
        }

  private object GetValue(Student stu)
        {
            object v = null;
            switch (expression)
            {
                case id:
                    v = stuID;
                    break;
                case name:
                    v = stuName;
                    break;
                default:
                    v = null;
                    break;
            }
            return v;
        }
    }測試一下好不好使

  static void Main(string[] args)
        {
            ListTest<Student> test = new ListTest<Student>();
            for (int i = ; i < ; i++)
            {
                Student stu = new Student(istringFormat(N_+(i)));
                testlistAdd(stu);
            }
            ConsoleWriteLine(元數據);
            for (int i = ; i < testlistCount;i++ )
            {
                ConsoleWriteLine(stringFormat(ID:{} Name:{} testlist[i]ID testlist[i]Name));
            }

  ConsoleWriteLine(Name 遞增);
            testSort(new StudentComparer(name true));
            for (int i = ; i < testlistCount; i++)
            {
                ConsoleWriteLine(stringFormat(ID:{} Name:{} testlist[i]ID testlist[i]Name));
            }
        }看看效果

  

  NET List的sort如何為我們排序用ILSpy反編譯可以看到在調用List<T>的sort()方法時內部調用的時 thisSort( thisCount null); 然後往裡面扒經過一系列異常處理後會調用 ArraySort<T>(this_items index count comparer); this_items是把List內容轉換成數組同樣再經歷一些列異常處理調用方法 ArraySortHelper<T>DefaultSort(array index length comparer); 再往裡就和我們上面寫的方法大同小異了只不過微軟加了很多異常處理和算法優化

  策略模式看清楚了上面這個例子我們就可以進入正題說說我們的策略模式了策略模式定義了一系列的算法並將每一個算法封裝起來而且使它們還可以相互替換策略模式讓算法獨立於使用它的客戶而獨立變化(原文The Strategy Pattern defines a family of algorithmsencapsulates each oneand makes them interchangeable Strategy lets the algorithm vary independently from clients that use it

  5366d0160924ab189a9f061935fae6cd7b890b16

  這個模式涉及到三個角色

  &#;環境(Context)角色持有一個Strategy類的引用
&#;抽象策略(Strategy)角色這是一個抽象角色通常由一個接口或抽象類實現此角色給出所有的具體策略類所需的接口
&#;具體策略(ConcreteStrategy)角色包裝了相關的算法或行為
相信大家可以分方便的把我們上面例子中的類對應上策略模式的角色IComparer接口是我們的抽象策略角色 ListTest<T> 類持有抽象策略的引用是環境(在Sort方法中其實可以把接口定義為類的屬性在構造函數中賦值不過不適合此場景畢竟並不是所有List都需要排序不能強制其接受一個可能會用不到的接口當然對每個實例都需要用某個策略的場景是合適的)毫無疑問我們實現IComparer抽象策略的類就是具體策略


From:http://tw.wingwit.com/Article/program/net/201311/12248.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.