一個OO的實例(二) |
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
TDBGrid是寫商用軟體最常用到的元件之一.可以上下捲,左右拉,還可以在裡面編輯...我的project裡,每個form都一定會有一個TDBGrid在下方,好方便user看到自己儲存的資料.但當user要在這個dbgrid中找到某一筆資料時,卻只能靠自己的眼力,拼命的移動滑鼠去找到自己要的那筆資料.所以,我想出一個所謂"遞增搜尋"的功能:user可以把focus移到dbgrid中的某個要搜尋的欄位,例如在電話的欄位裡.後當user按下"0"的時候,cursor會自動移到號碼為0開頭的該筆資料,再馬上按下"9",然後cursor會接著移到"09"開頭的該筆資料,再馬上按下3,cursor移到"093"開頭的資料....,這樣,user可以在dbgrid上只按幾個鍵就可以快速的找到要找的資料.如果user超過1秒沒有按鈕,那麼下次user再按時,先前的093就被清除,重新再來一次. 要做到這樣的功能其實很容易:我可以在form的private裡,宣告一個LastKeyTime,儲存上一次按鈕的時間,宣告一個SearchWord,儲存user按下的鍵.然後,在DBGrid的OnKeyPress去檢查,把目前的時間減掉LastKeyTime裡的時間,如果沒有超過1秒,就把得到的Key加入到SearchWord裡,然後對DBGrid連著的DataSet呼叫其Locate方法,以DBGrid.SelectedField做為搜尋的欄位,以SearchWord做為搜尋的值,加上[loCaseInsensitive,loPartialKey]兩個參數,讓cursor可以移到該筆資料.如果按下的時間與上次按鈕的時間超過一秒,就把收到的Key值蓋掉SearchWord,然後再呼叫Locate去搜尋.另外,為了讓user更好控制,在MainForm的toolBar上,再加個TToolButton,當壓下時,表示啟動這個功能,彈起來時,就不啟動這個功能.程式的複雜度也不會增加太多,只要在DBGrid.OnKeyPress開頭先去檢查MainForm的這個按鈕是否被壓下,做為是否執行的判斷即可.另外,為了因應可能有user反應較慢,希望延長兩次按鍵的時間到1.5秒,所以把1秒設一個常數,如果要改,就改這個常數值即可....
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
嗯,一切都很完美,只有一件事情不對勁:我的project有8成的畫面有dbgrid,每個form都要做到這個功能,我要改的form有多少,而且每個 class="code">
type
TIncSearch = class(TObject)
private
FLastKeyTime:TTimeStamp; //上一次輸入字元的時間
FDestObj:TWinControl;
FDataSet:TDataSet; //要搜尋的DataSet
FActive:Boolean;
FSearchWord:String; //要搜尋的字串
FInterval: Integer;
procedure ActiveKeyPress(Sender: TObject; var Key: Char);
procedure SetDestObj(const Value: TWinControl);
procedure LocateDataSet;
procedure SetActive(const Value: Boolean);
public
constructor Create;virtual;
destructor Destroy;override;
property DestObj:TWinControl read FDestObj write SetDestObj;
property Active:Boolean read FActive write SetActive;
property Interval:Integer read FInterval write FInterval; //接受字元的時間間隔
end;
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
然後在form.Create裡增加如下程式:
FSearcoObj:=TIncSearch.Create; FSearcoObj.DestObj:=DBGrid1;這裡做補充個說明: FDestObj:TWinControl; 指被作用的元件,也就是會觸發OnKeyPress的dbgrid.定義成TWinControl,是考慮到如果這個功能後面不只會在DBGrid上,也會在其他的物件上時,也可以放進來(有沒有可能是DBGrid以外的元件我也不知道,反正留著也沒有壞處) 到這裡,各位是否了解OO要怎麼用了.沒錯,其實OO的用法就是這麼好用及簡單,只要多動點腦筋,其實coding可以更有效率. 另外,再舉個OO寫法的好處.由於我的project,有dbgrid的form,都從一個已定義好的form繼承下來,所以,讓project裡所以有的form都有這個功能,我只改了兩個pas,一個是實作這個物件的pas檔,另外一個,就是那個被繼承的form,從這個form繼承下去的form,完全不用改,酷吧!! |
renth555
一般會員 發表:32 回覆:65 積分:19 註冊:2003-02-17 發送簡訊給我 |
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
|
thomas0728
中階會員 發表:112 回覆:260 積分:89 註冊:2002-03-12 發送簡訊給我 |
講到物件導向,大家一定都會說就封裝,繼承與多型,但大部份是小和尚念經,有口無心,跟本無法體會其中的精髓,就算知道封裝,繼承與多型如何實作,其實這三者也並不是物件導向的全部,就以繼承來說,很多初學把繼承看的很重要,是程式語言裡最重要的發明,其實在物件導向的領域裡有一條規則是這樣說的,要盡量使用合成/聚合,而不要使用繼承,原因在於繼承是一種靜態的關係,無法做到動態而有彈性的變化,這可能是出乎很多人的意料之外,雖然繼承是多型的基礎,但透過合成/聚合 也可以做到多型的功能,而且比繼承的多型更具彈與穏定 ,但目前的物件導向教學都在封裝,繼承與多型上打轉,並沒有碰觸到物件導向設計的真正核心,只是在繼承上打轉,配合一點多型的功能,這樣真的還是無法寫出真正穏而可維護的程式.
那如何真正進入物件導向的世界,也許可以從 DESIGN PATTERNS 下手去體會物件導向的真正精髓,DESIGN PATTERNS 可以讓你體會到什麼叫要針對抽象編碼而不要對具體編碼,它也可以讓你養成優雅的思考程式如何佈局,而不在是暴力解法,不是有一句話,人一思考上帝就發笑嗎?
另外多看一點企業建模的資料,也有助於重另一種角度來看 OO,物件導向真的不是只有封裝,繼承與多型,只會這三個觀念還是無法寫出國際性的程式,台灣人要加油,軟體業要工業化 OO 技術佔很重的關鍵地位,但只有 OO 三要素也難成大局 如果愛情也有味覺
那麼 有沒有ㄧ種愛
微微泛酸 不太苦澀 有點甜密
嚐起來的滋味讓人想起幸福
Thomas Chiou
------
Thomas Chiou |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
顯然thomas0728大大對於OO的隔局要比我大多了. 老實說,對於OO的書籍,國內我找不到,除了DESIGN PATTERNS與Inside VCL.而國外的書籍,對於大部分的programmer而言(包含我在內),都有一定的距離與隔閡,要涉獵到這方面的資訊真的不容易,更何況要用到自己實際的例子上. 以我的例子而言,OO的寫法,有大半來自於VCL的source code.在看source code時,常常會發現那些人真的叫天縱英才,可以這樣來布局程式碼.我認為,其實programmer也不必為了OO的名字,為了這些理論名稱,而苦苦背訟,重點還在於實作,在於讓自己的程式碼比較好控管. 舉個例子而言,後代繼承的物件,在override父代物件的方法時,我有可能會把inherited擺在第一行,也可能把inherited擺在中間,也甚至根本不去inherited.會怎麼做,就看實際需求而定.一開始我這樣寫時,有人跟我說,那這樣豈不是很鬆散,當時,我無言以對.但,我知道,這樣做讓我可以寫最少的code.這是兩年前的事.直到後來,李維大師的 Inside VCL 一書出來,我才曉得原來我用的方法是對的(而且這樣的用法,還有個名字咧). 總之,重點仍在於實作.把OO的寫法用於實作上,不要讓返覆的剪貼動作佔掉coding工作的全部,多花點時間抬頭~~想想是否有更smart的做法,這樣才有助於coding經驗的累積.
引言: 講到物件導向,大家一定都會說就封裝,繼承與多型,但大部份是小和尚念經,有口無心,跟本無法體會其中的精髓,就算知道封裝,繼承與多型如何實作,其實這三者也並不是物件導向的全部,就以繼承來說,很多初學把繼承看的很重要,是程式語言裡最重要的發明,其實在物件導向的領域裡有一條規則是這樣說的,要盡量使用合成/聚合,而不要使用繼承,原因在於繼承是一種靜態的關係,無法做到動態而有彈性的變化,這可能是出乎很多人的意料之外,雖然繼承是多型的基礎,但透過合成/聚合 也可以做到多型的功能,而且比繼承的多型更具彈與穏定 ,但目前的物件導向教學都在封裝,繼承與多型上打轉,並沒有碰觸到物件導向設計的真正核心,只是在繼承上打轉,配合一點多型的功能,這樣真的還是無法寫出真正穏而可維護的程式. 那如何真正進入物件導向的世界,也許可以從 DESIGN PATTERNS 下手去體會物件導向的真正精髓,DESIGN PATTERNS 可以讓你體會到什麼叫要針對抽象編碼而不要對具體編碼,它也可以讓你養成優雅的思考程式如何佈局,而不在是暴力解法,不是有一句話,人一思考上帝就發笑嗎? 另外多看一點企業建模的資料,也有助於重另一種角度來看 OO,物件導向真的不是只有封裝,繼承與多型,只會這三個觀念還是無法寫出國際性的程式,台灣人要加油,軟體業要工業化 OO 技術佔很重的關鍵地位,但只有 OO 三要素也難成大局 如果愛情也有味覺 那麼 有沒有ㄧ種愛 微微泛酸 不太苦澀 有點甜密 嚐起來的滋味讓人想起幸福 Thomas Chiou |
pwipwi
版主 發表:68 回覆:629 積分:349 註冊:2004-04-08 發送簡訊給我 |
對於thomas0728大大的文章,我個人有些不同的見解… OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。比如大家常聽到的Cplusplus多型上的缺點,並不代表那就是OO的多型缺點。其他語言比如smalltalk、Delphi,在這方面做得比Cplusplus更好。 至於thomas0728大大提到的"繼承是一種靜態的關係,無法做到動態而有彈性的變化"我個人覺得不是很同意,如Delphi用上了metaclass,幾乎是完全的動態型別,非常出色的實作方法。不知道"繼承是一種靜態的關係"是指那個部份呢?
|
thomas0728
中階會員 發表:112 回覆:260 積分:89 註冊:2002-03-12 發送簡訊給我 |
很多人以為採 oo 的機制來寫程式,就可以突然間少寫一些程式,事實上這是一個誤會,該寫的該做的一項也少不了,比如說,每個欄位的輸入檢查及前後欄位檢查,事實上這些都是無法避免的,只是寫的地方與方式不太一樣,要思考的方式也不太一樣.
OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。 這句話本身是對的,但 metaclass 是 delphi 獨有的語言機制,如果今天要用 c++ 來實作恐怕浱不上用場,所以討論時就不以一種語言特有的機制來討論,比較會有普遍性,況且使用
------
Thomas Chiou |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
個人對於pwipwi版主所說的metaclass,有興趣想多瞭解一點,可否請版主概略述敘一下內容,謝謝!!
引言: 對於thomas0728大大的文章,我個人有些不同的見解… OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。比如大家常聽到的Cplusplus多型上的缺點,並不代表那就是OO的多型缺點。其他語言比如smalltalk、Delphi,在這方面做得比Cplusplus更好。 至於thomas0728大大提到的"繼承是一種靜態的關係,無法做到動態而有彈性的變化"我個人覺得不是很同意,如Delphi用上了metaclass,幾乎是完全的動態型別,非常出色的實作方法。不知道"繼承是一種靜態的關係"是指那個部份呢? |
hahalin
版主 發表:295 回覆:1698 積分:823 註冊:2002-04-14 發送簡訊給我 |
|
pwipwi
版主 發表:68 回覆:629 積分:349 註冊:2004-04-08 發送簡訊給我 |
|
thomas0728
中階會員 發表:112 回覆:260 積分:89 註冊:2002-03-12 發送簡訊給我 |
metaclass在李維的 高等 DELPHI 程式技術一書有提到,另外在 DELPHI 學習筆記裡也有到,但以上這二本書好像都絶版了,另外美商歐萊禮出的一本書裡也有介紹,書名忘了,不過 METACLASS 只是動態產生類別的機制,不過用 DESIGN PATTERNS 的 FACTORY MENTH 或 ABSTRACT FACTORY 會更好用 如果愛情也有味覺
那麼 有沒有ㄧ種愛
微微泛酸 不太苦澀 有點甜密
嚐起來的滋味讓人想起幸福
Thomas Chiou
------
Thomas Chiou |
den3do
一般會員 發表:2 回覆:7 積分:1 註冊:2003-01-15 發送簡訊給我 |
學習以 OO 的思考方式來設計程式 看到這句話小的真的有粉大的感觸,
小的在寫一隻程式時,只會想個大略的流程,
然後開始動工,寫著寫著才發現ㄟ,
這個From的Code 好多ㄛ,以後維護一定粉難,
不過管他的,先寫再說(熱血中 or 趕工中),
有天程式ok了,要開始整理程式碼,
才突然發現,有些東東弄成物件會比較好ㄟ,
不過木已成舟,
自己寫好玩的程式當然還可以改寫,
但是如果是公司的程式,沒Bug就菩薩保佑了,
還改寫勒..... 幾次下來,就想好好研究一下所謂的 > ㄞ...
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
1.關於metaclass,經thomas0728的解釋,大概已有點概念了.不曉得對不對,印證一下,像以呼叫TComponentFactory.Create去產生物件,是否就是屬於這類?還請大大指教一二. 2.關於den3do與hahalin的想法,也是我現在在思考的問題.目前關於OO的部分,我僅限於用在GUI的界面控制上,至於系統的business rule(像hahalin大大所舉的ERP的例子),我幾乎都是實作在DB的store procedure上.一方面是performance的考量,一方面也是可以大量減少Delphi coding的量.藉此機會請教各位大大,關於business rule,是否有人以OO的方式實作的? 3.thomsa0728說的以OO的方式來思考,我很認同.其實,很多時候,我也一樣是在Object inspector裡點兩點去寫程式的.只是我比較懶,同樣的程式寫多了就不想再寫,稍微多花點時間全盤思考一下,結果就發現,用OO的寫法,可以達到code大量重覆使用的目的.至於如何以OO的方式來思考,其實很難具體描述,但有一點心得,很多OO書籍裡寫的那種"門","關門","拉下關門"....等的,如den3do所提的,很抽象.在思考自己的程式要如何OO時,不要把那個放在腦子裡...,這是我個人的小心得,有錯還請指正.
|
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
自己回應自己;
<>< face="Verdana, Arial, Helvetica">引言:
1.關於metaclass,經thomas0728的解釋,大概已有點概念了.不曉得對不對,印證一下,像以呼叫TComponentFactory.Create去產生物件,是否就是屬於這類?還請大大指教一二.
上面我說的那是錯的.正解在Delphi的online help裡己找到了,有興趣的可以參考Object Pascal Language Guide裡的"Class-reference types"及"Class-reference types"及"Constructors"等章節.剛好今天系統裡需要這樣的運用,才發現這即是所謂的metaClass 有錯還請糾正
|
thomas0728
中階會員 發表:112 回覆:260 積分:89 註冊:2002-03-12 發送簡訊給我 |
metaclass 是從 smalltalk 借來的,可以處理二種問題,一.在程式執行時才能決定類別二,在決定了類別後,才可以使用這個類別來建立使用者所要的物件
也就是說 metaclass 是類別的類別
舉個例子就明白了
var pDataset:TDataset; begin .... .... if 使用者選擇建立 TTable then begin pDataSet:=TTable.create(application); pDataSet.DatabaseName:='dbdemos'; ...... end else if 使用者選擇建立 TQuery then begin pDataSet:=TQuery.create(application); ..... end if 使用者選擇建立 TStoredProc then begin pDataSet:=TStoredProc.create(application); ..... end; {/code] 在上面程式中我們先宣告一個資料集物件變數,在根據使用者所選擇而進行行動態建立真正要的物件,之所以可以這樣用是因為 object pascal 支援 oo 的多型功能,透過多型就可輕易的解決動庇產生物件的問題 但如果換做另一種情形時,就沒那麼簡單了 如果我們希望在程式執行時動態的建立一個物件,但這個物件的類別可能有好幾個,因此我們連這個物件的類別種類休不能在撰寫程式時決定,一定要根據程式執行時決定,也就是一.必須在程式執行時才能決定類別,二.在決定類別之後才可以使用者個類別來建立物件 要宣告一個 metaclass 如下不知從以上的程式碼各位是否看出 metaclass 的功 結論就是,根據 metaclass 來動態建立類別及物件時,這些類別的同祖先類別是同一個,物件所要使用的方法的參數也是一致的 學會 metaclass 這樣才是愛台灣與愛 delphi 我就是愛 delphi ,謀你是買安哪 < >< > 如果愛情也有味覺 那麼 有沒有ㄧ種愛 微微泛酸 不太苦澀 有點甜密 嚐起來的滋味讓人想起幸福 Thomas ChiouTControlClass=class of TControl;比如 [code] procedure TForm1.FormCreate(sender:TObject); begin with classList.items do begin addobject('tedit',tobject(tedit)); addobject('tcheckbox',tobject(tcheckbox)); addobject('tbutton',tobject(tbutton)); .... end; vlasslist.itemindex:=0; end; 在此是將這個程式可以動態產生的物件及其類別放入 ClassList 這個 TComboBox 特件中 procedure TForm1.Button1click(sender:TObject); var Reference:TControlClass Instance:TControl; Text:array[0..255] of char; begin Reference:=TControlClass(classlist.items.objects[classlist.itemindex]); instance.parent:=reference.create(self); instance.left:=strtoint(xpos.text); if instance is twincontrol then sendmessage(twincontrol(instance).handle,wm_settext,0,longint(strpcopy(text,textprop.text))); end; end; 根據 combobox 中的類別來建立物件,此時 metaclass 便發揮了功能
------
Thomas Chiou |
change.jian
版主 發表:29 回覆:620 積分:439 註冊:2003-06-02 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |