如何讓 TList 的衍生物件, 專門放入特定 Class Object? |
尚未結案
|
Diviner
初階會員 發表:36 回覆:112 積分:34 註冊:2002-03-13 發送簡訊給我 |
有沒有辦法把 TList Inherit 出一個新的 TMyList class, 而它專門存取一個特定的 Class Object (例如 TMyObj) 呢? 即是說, 我若果寫 MyList1.Add(Button1), 而 Button1 不是 TMyObj class 的話會出 compile error, 又 MyList1[0] 不用做 Type casting 就可以使用 TObj 的 property/method, 可以嗎? --
小卜子 發表人 - diviner 於 2004/04/20 19:15:03
------
-- 小卜子 |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
您好,我建議不要從TList繼承下來,改建另一個,底下是範例:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMyObj = class(TComponent) private FProp:String ; FName: TComponentName; procedure SetProp(const Value: string); procedure SetName(const Value: TComponentName); public property Name: TComponentName read FName write SetName; property Prop:string read FProp write SetProp; end; TMyList = class(TObject) private FList:TStringList; function GetItem(Index: Integer): TMyObj; procedure SetItem(Index: Integer; const Value: TMyObj); public constructor Create; destructor Destroy;override; property Items[Index:Integer]:TMyObj read GetItem write SetItem; function Add(MyObj:TMyObj):Integer; end; TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ListBox1DblClick(Sender: TObject); private List:TMyList; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyList } function TMyList.Add(MyObj: TMyObj): Integer; begin FList.AddObject(MyObj.Name,MyObj); end; constructor TMyList.Create; begin FList:=TStringList.Create; end; destructor TMyList.Destroy; begin FList.Free; inherited; end; function TMyList.GetItem(Index: Integer): TMyObj; begin Result:=TMyObj(FList.Objects[Index]); end; procedure TMyList.SetItem(Index: Integer; const Value: TMyObj); begin FList.Objects[Index]:=Value; end; { TMyObj } procedure TMyObj.SetName(const Value: TComponentName); begin FName := Value; if FProp = '' then FProp := Value; inherited; end; procedure TMyObj.SetProp(const Value: string); begin FProp := Value; end; procedure TForm1.Button1Click(Sender: TObject); var sName:String; MyObj:TMyObj; begin sName:='MyObj'; if InputQuery('輸入物件的名字','新建的TMyObj名字',sName) then begin MyObj:=TMyObj.Create(Self); MyObj.Name:=sName; List.Add(MyObj); ListBox1.Items.Add(MyObj.Name); end; end; procedure TForm1.FormCreate(Sender: TObject); begin List:=TMyList.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin List.Free; end; procedure TForm1.ListBox1DblClick(Sender: TObject); var Index:Integer; begin Index:=ListBox1.ItemIndex; if Index>-1 then ShowMessage(List.Items[Index].Prop); end; end.在procedure TForm1.ListBox1DblClick(Sender: TObject)裡,就是你要的,不用經過Type casting就可以直接叫用TObj的方法/屬性 |
Diviner
初階會員 發表:36 回覆:112 積分:34 註冊:2002-03-13 發送簡訊給我 |
回 change.jian, 先謝謝您。 若我 Inherit TList, 而這樣寫(如下), 應該會好一點, 因為你的方法是把 Is A 化為 Has A, 於是很多 TList 的特性都消失掉, 例如連 Count 都失去了, 於是, 我的 TMyList 便要橋接很多 Property 及 Method 才行。不如你看看我以下的程式碼, 看看好不好, 有沒有副作用:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TMyObj = class name: String; constructor Create(const s: String); procedure ShowName; end; TMyList = class(TList) protected function Get(Index: Integer): TMyObj; procedure Put(Index: Integer; Item: TMyObj); public function Add(Item: TMyObj): Integer; property Items[Index:Integer]:TMyObj read Get write Put; default; end; TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} { TMyObj } constructor TMyObj.Create(const s: String); begin name := s; end; procedure TMyObj.ShowName; begin ShowMessage(name); end; { TMyList } function TMyList.Add(Item: TMyObj): Integer; begin result := Inherited Add(Item); end; function TMyList.Get(Index: Integer): TMyObj; begin result := Inherited Get(Index); end; procedure TMyList.Put(Index: Integer; Item: TMyObj); begin Inherited Put(Index, Item); end; procedure TForm1.Button1Click(Sender: TObject); var o1, o2: TMyObj; List: TMyList; i: Integer; begin o1 := TMyObj.Create('o1'); o2 := TMyObj.Create('o2'); List := TMyList.Create; List.Add(o1); List.Add(o2); for i := 0 to List.Count - 1 do List.Items[i].ShowName; // 也可直接寫成 List[i].ShowName; List.Free; o1.free; o2.free; end; end.-- 小卜子 發表人 - diviner 於 2004/04/21 11:31:27
------
-- 小卜子 |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
|
Diviner
初階會員 發表:36 回覆:112 積分:34 註冊:2002-03-13 發送簡訊給我 |
引言: 嗯,不錯,確實簡潔許多.只是以我一向的經驗,我都是直接從TObject繼承下來,因為常常會有客戶要改變需求,或者有一些功能當初沒想到,如果從TList繼承下來的話,那麼物件就一定會長成TList的形狀,當然,後面也可以自己再新增... 如果我的話,我會把這個物件定義成一個manager的角色,負責管理TMyObj物件,包含TMyObj.Create及TMyObjFree等全由這個物件控制,這樣程式碼的管理會更方便我認為是這樣, 當原來的 TMyList 已發展到超越了 List 的本質的時候, 其實是另一個物件了。介時, 應該建立一個新的 Class, 來管理這個 TMyList 不遲。 無論如何, 謝謝您回答。 -- 小卜子 發表人 - diviner 於 2004/04/21 16:40:18
------
-- 小卜子 |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
|
yangshengfa
一般會員 發表:1 回覆:16 積分:3 註冊:2003-09-06 發送簡訊給我 |
|
ccchen
版主 發表:61 回覆:940 積分:1394 註冊:2002-04-15 發送簡訊給我 |
|
Diviner
初階會員 發表:36 回覆:112 積分:34 註冊:2002-03-13 發送簡訊給我 |
引言:我想到這個, 只是我也想到, 若一個 List 發展到 List 無論如何承繼都不敷應用的時候, 那麼它跟本就不是一個 List, 而是一個「內含 List 的另一件東西」, 那麼, 舊的使用 TMyList 的部份, 應該是無需改變的, 而新的物件 (例如是 TMyObject) 應該不是舊有的程式部份的要求, 而是新的程式部份, 有新的要求, 所以才需要 TMyObject 的誕生來應付… 若有個具體一點的例子或者會好說一點。 -- 小卜子引言: 我認為是這樣, 當原來的 TMyList 已發展到超越了 List 的本質的時候, 其實是另一個物件了。介時, 應該建立一個新的 Class, 來管理這個 TMyList 不遲。 無論如何, 謝謝您回答。 -- 小卜子 發表人 - diviner 於 2004/04/21 16:40:18我突然想到,如果屆時才用另一個新的物件的話,那麼原本呼叫TMyList的所有程式不是得要一併跟著修改才行....,還是另有其他的方法解決?
------
-- 小卜子 |
Diviner
初階會員 發表:36 回覆:112 積分:34 註冊:2002-03-13 發送簡訊給我 |
|
ccchen
版主 發表:61 回覆:940 積分:1394 註冊:2002-04-15 發送簡訊給我 |
引言:Delphi的Souce Code內有很多例子, 例如StatusBar上之Panels, TListView之Columns, 或TDBGrid之Columns均是, 你可以看看SouceCode(Statusbar及TListView均在Comctrls.pas中) 主要關鍵在於 1. 繼承至TCollectionItem之Class須Override Assign method(其他看須要而定) 2. 繼承至TCollection之Class須Implement Item[] property, 及其Read/write method 看看Source code中此3 method之implement, 應該就可以知道如何做了引言: 如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊我不知道這個, 舉個小例子好嗎? |
ccchen
版主 發表:61 回覆:940 積分:1394 註冊:2002-04-15 發送簡訊給我 |
引言:Delphi的Souce Code內有很多例子, 例如StatusBar上之Panels, TListView之Columns, 或TDBGrid之Columns均是, 你可以看看SouceCode(Statusbar及TListView均在Comctrls.pas中) 主要關鍵在於 1. 繼承至TCollectionItem之Class須Override Assign method(其他看須要而定) 2. 繼承至TCollection之Class須Implement Item[] property, 及其Read/write method 看看Source code中此3 method之implement, 應該就可以知道如何做了引言: 如果要專門存取一個特定的 Class Object,可以考慮繼承TCollection及TCollectionItem, 因為這正是此兩Class設計的目的啊我不知道這個, 舉個小例子好嗎? |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |