在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
簡單的說,泛型程式設計允許開發人員撰寫可泛用的運算法則,這些運算法則能夠使用於各種不同的資料型態,因此一旦開發人員開發完成這些泛用的運算法則,其他的開發人員就可以根據需要的處理資料型態帶入泛用的運算法則來完成運算的工作。例如Delphi最早提供的TList容器類別在實作時由於寫死是使用TObject的資料型態(類別型態),因此開發人員只能在TList中使用TObject樣例。但是TList容器提供的運算法則其實是能夠應用於任何型態的,而且開發人員在許多情形中也希望能夠使用TList來暫時處理一些程式碼中的物件,而不只是TObject樣例。 因此所謂泛型的TList就是讓TList提供的運算法則能夠適用於各種不同的資料型態(類別型態),例如讓TList可以處理字串,整數,浮點數或是任何開發人員定義的類別型態。在一般的程式語言中泛型是使用<T>符號來代表的,其中的代表Type或是Template的意思,因此泛型的TList就是: TList + <T> = TList<T> 因此要讓TList處理字串,就使用TList<String>, 因此要讓TList處理TComponent,就使用TList<TComponent>, 以此類推,所以使用泛型程式設計並不困難,把<T>代換成你要使用的資料型態(類別型態)即可。 當然,在要使用泛型容器類別之前也是需要建立它們才能使用,在建立泛型容器類別時,記得也要代入你建立泛型容器類別之後要在其中使用的資料型態(類別型態),例如前面的例子中,要讓TList處理字串就必須如下的建立TList泛型容器類別物件: var ltstring : TList<String>; begin … tlstring := TList<String>.create; 讓TList處理TComponent必須如下的建立TList泛型容器類別物件: var tlcomponent: TList<TComponent>; begin … tlcomponent := TList<Tcomponent>.create; 以此類推。 下面列出了Delphi 2009中提供的泛型容器類別:
使用TObjectList和TEnumerator
排序泛型容器類別
另外一個經常使用的情形是需要排序泛型容器類別之中的元素,由於泛型容器類別可以包含任何型態的物件,因此如何排序其中的元素物件應該是根據不同的型態而異的,因此開發人員必須提供如何排序的程式碼給泛型容器類別來呼叫以決定元素之間的次序。 TObjectList<T>提供了兩個排序方法: procedure Sort; overload; procedure Sort(const AComparer: IComparer<T>); overload; 其中第一個Sort是使用內定的排序方式,開發人員如果需要定義自己的排序法則就需要使用第二個Sort方法。第二個Sort方法接受一個IComparer<T>介面的參數,IComparer<T>定義如下: IComparer<T> = interface function Compare(const Left, Right: T): Integer; end; IComparer<T>介面定義了Compare方法,它回傳整數,-1代表小於,0代表等於而1代表大於。 因此開發人員需要實作一個實作IComparer<T>介面的類別,再把這個類別的物件傳遞給上面的第二個Sort方法來實際的排序。 實作IComparer<T>最簡單的方法是定義一個從TComparer<T>類別繼承下來的子類別,因為Delphi2 2009已經定義了如下的TComparer<T>類別: TComparer<T> = class(TInterfacedObject, IComparer<T>) public class function Default: IComparer<T>; class function Construct(const Comparison: TComparison<T>): IComparer<T>; function Compare(const Left, Right: T): Integer; virtual; abstract; end; 因此我們要排序glProduct之中的TProduct物件,讓我們定義TproductLineComparer類別,它從TComparer<T>類別繼承下,我們只需要複載實作Compare來撰寫如何排序TProduct物件。在下面的程式碼中我們先以TProduct的Category特性值來排序,如果Category特性值相同,就以TProduct的Version特性值來做子排序條件: type TProductLineComparer = class(TComparer<TProduct>) public function Compare(const Left, Right: TProduct): Integer; override; end; implementation { TProductLineComparer<T> } function TProductLineComparer.Compare(const Left, Right: TProduct): Integer; begin Result := 0; if (Left.GetCategory < Right.GetCategory) then Result := -1 else if (Left.GetCategory > Right.GetCategory) then Result := 1 else begin if (Left.GetVersion < Right.GetVersion) then Result := -1 else if (Left.GetVersion > Right.GetVersion) then Result := 1; end; end; 有了TProductLineComparer之後就可以使用下面的程式碼來排序glProducts之中所有TProduct物件的次序了: procedure TForm17.btn依產品線排序Click(Sender: TObject); var aPLC : TProductLineComparer; begin aPLC := TProductLineComparer.Create; try glProduct.Sort(aPLC); DisplayProducts(glProduct.GetEnumerator); finally aPLC.Free; end; end; 上面的程式碼先建立TProductLineComparer物件,傳遞給Sort做為參數即可。 下圖是先呼叫TEnumerator顯示glProducts中所有的TProduct物件,讀者可以看到物件是以我們加入glProducts之中的次序顯示,而呼叫依產品線排序之後TProduct物件就以正確的產品種類+產品版本的次序來顯示。
結合匿名方法
現在讓我們稍為展示如何結合泛型和匿名方法。 Delphi 2009新的程式語言功能之一就是匿名方法,匿名方法主要的功能是允許開發人員在程式碼中定義一些小而簡單的程式碼來使用,而這些小而簡單的程式碼不需要正式定義成方法,而是使用完之後就不再需要的情形之中。此外匿名方法可以和泛型程式設計一起使用。現在讓我們再對glProducts中的TProduct進行排序,但是我們只需要對Delphi的產品排序。 因此我們需要先過濾出Delphi的產品物件,再根據過濾出Delphi的產品物件進行排序,下面的程式碼就可以完成這個工作: 001 procedure TForm17.btn依Delphi版本排序Click(Sender: TObject); 002 var 003 aDelphiFilter : TFunc<TProduct, Boolean>; 004 ltDelphi: TList<TProduct>; 005 aEnum : TEnumerator<TProduct>; 006 aPLC: TProductLineComparer; 007 begin 008 ltDelphi := TList<TProduct>.Create; 009 try 010 aEnum := glProduct.GetEnumerator; 011 aDelphiFilter := function (aProduct : TProduct) : Boolean 012 begin 013 Result := False; 014 if (aProduct.GetCategory = 'Delphi') then 015 Result := True; 016 end; 017 018 while aEnum.MoveNext do 019 begin 020 if (aDelphiFilter(aEnum.Current)) then 021 ltDelphi.Add(aEnum.Current); 022 end; 023 024 aPLC := TProductLineComparer.Create; 025 try 026 ltDelphi.Sort(aPLC); 027 Self.lb產品資料.items.Add('========依Delphi產品線排序=========='); 028 DisplayProducts(ltDelphi.GetEnumerator); 029 finally 030 aPLC.Free; 031 end; 032 finally 033 ltDelphi.Free; 034 end; 035 end; 上面程式碼的邏輯很簡單,我們使用一個匿名方法從glProduct中過濾出Delphi的產品,放入另外一個TList<T>泛型容器類別之中,最後再使用前面介紹的TProductLineComparer來排序。 在上面的程式碼中,003行的aDelphiFilter宣告的型態是TFunc<TProduct, Boolean>,那麼是TFunc<TProduct, Boolean>呢? TFunc就是一個接受泛型的匿名方法,它定義在SysUtils程式單元中,它的原型如下: TFunc<T,TResult> = reference to function (Arg1: T): TResult; 事實上在Delphi 2009的SysUtils程式單元中已經定義了許多通用的泛型匿名方法可以讓開發人員使用,它們的定義如下: // Generic Anonymous method declarations type TProc = reference to procedure; TProc<T> = reference to procedure (Arg1: T); TProc<T1,T2> = reference to procedure (Arg1: T1; Arg2: T2); TProc<T1,T2,T3> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3); TProc<T1,T2,T3,T4> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4); TFunc<TResult> = reference to function: TResult; TFunc<T,TResult> = reference to function (Arg1: T): TResult; TFunc<T1,T2,TResult> = reference to function (Arg1: T1; Arg2: T2): TResult; TFunc<T1,T2,T3,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3): TResult; TFunc<T1,T2,T3,T4,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4): TResult; TPredicate<T> = reference to function (Arg1: T): Boolean; 回到前面的程式碼中,在011到016定義了匿名方法並且指定給匿名方法變數aDelphiFilter,接著藉由TEnumerator物件一一的存取glProduct中的元素,並且使用aDelphiFilter來過濾出Delphi的產品,最後在026行呼叫ltDelphi的Sort方法並且傳入TProductLineComparer做為參數。 下面是執行這個方法的結果畫面: OK,下次讓我解釋如何結合使用TDictionary<T>以及匿名方法更為技術面的內容,Have Fun!。
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论