全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2856
推到 Plurk!
推到 Facebook!

一個OO的實例(二)

 
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#1 引用回覆 回覆 發表時間:2004-10-16 01:36:16 IP:61.229.xxx.xxx 未訂閱
前情提要,參考這裡:
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#2 引用回覆 回覆 發表時間:2004-10-16 01:42:01 IP:61.229.xxx.xxx 未訂閱
相較於結構化,物件導向的觀念就顯得更有彈性了.其實說穿了,物件就是一堆的function,procedure組合起來的.就結構化來說,為了不要一次看到那麼多的code,所以把程式切成一塊塊,但也因為如此,所以變成每一小塊的程式功能不會太複雜或者太多程式碼(不過,我仍然有維護過一個procedure裡寫了近二百行的程式碼,我在猜那個程式的原創者是不是故意的,要讓後面維護的人做不下去).而物件藉由整合若干個 >).不過,可惜的是大部分的
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#3 引用回覆 回覆 發表時間:2004-10-16 01:46:08 IP:61.229.xxx.xxx 未訂閱
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

發送簡訊給我
#4 引用回覆 回覆 發表時間:2004-10-16 01:51:14 IP:61.229.xxx.xxx 未訂閱
嗯,一切都很完美,只有一件事情不對勁:我的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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2004-10-16 01:55:06 IP:61.229.xxx.xxx 未訂閱
然後在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

發送簡訊給我
#6 引用回覆 回覆 發表時間:2004-10-16 20:32:24 IP:61.56.xxx.xxx 未訂閱
請問我在 Unit2.cpp 內寫一個 class 在來我要如何制作一個 pas 檔 然後在把這個 class pas 檔加入另一個專案呢 請前輩教我
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#7 引用回覆 回覆 發表時間:2004-10-16 22:05:51 IP:218.161.xxx.xxx 未訂閱
Unit2.cpp 應該不是Delphi的檔案吧?!    我是Delphi寫的,如果你不是用Delphi的話,那麼可能你要自己把pascal轉成你的語法了    
引言: 請問我在 Unit2.cpp 內寫一個 class 在來我要如何制作一個 pas 檔 然後在把這個 class pas 檔加入另一個專案呢 請前輩教我
thomas0728
中階會員


發表:112
回覆:260
積分:89
註冊:2002-03-12

發送簡訊給我
#8 引用回覆 回覆 發表時間:2004-10-17 05:07:52 IP:61.70.xxx.xxx 未訂閱
講到物件導向,大家一定都會說就封裝,繼承與多型,但大部份是小和尚念經,有口無心,跟本無法體會其中的精髓,就算知道封裝,繼承與多型如何實作,其實這三者也並不是物件導向的全部,就以繼承來說,很多初學把繼承看的很重要,是程式語言裡最重要的發明,其實在物件導向的領域裡有一條規則是這樣說的,要盡量使用合成/聚合,而不要使用繼承,原因在於繼承是一種靜態的關係,無法做到動態而有彈性的變化,這可能是出乎很多人的意料之外,雖然繼承是多型的基礎,但透過合成/聚合 也可以做到多型的功能,而且比繼承的多型更具彈與穏定 ,但目前的物件導向教學都在封裝,繼承與多型上打轉,並沒有碰觸到物件導向設計的真正核心,只是在繼承上打轉,配合一點多型的功能,這樣真的還是無法寫出真正穏而可維護的程式. 那如何真正進入物件導向的世界,也許可以從 DESIGN PATTERNS 下手去體會物件導向的真正精髓,DESIGN PATTERNS 可以讓你體會到什麼叫要針對抽象編碼而不要對具體編碼,它也可以讓你養成優雅的思考程式如何佈局,而不在是暴力解法,不是有一句話,人一思考上帝就發笑嗎? 另外多看一點企業建模的資料,也有助於重另一種角度來看 OO,物件導向真的不是只有封裝,繼承與多型,只會這三個觀念還是無法寫出國際性的程式,台灣人要加油,軟體業要工業化 OO 技術佔很重的關鍵地位,但只有 OO 三要素也難成大局 如果愛情也有味覺 那麼 有沒有ㄧ種愛 微微泛酸 不太苦澀 有點甜密 嚐起來的滋味讓人想起幸福 Thomas Chiou
------
Thomas Chiou
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#9 引用回覆 回覆 發表時間:2004-10-17 10:47:11 IP:61.229.xxx.xxx 未訂閱
顯然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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2004-10-17 15:19:09 IP:140.112.xxx.xxx 未訂閱
對於thomas0728大大的文章,我個人有些不同的見解… OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。比如大家常聽到的Cplusplus多型上的缺點,並不代表那就是OO的多型缺點。其他語言比如smalltalk、Delphi,在這方面做得比Cplusplus更好。 至於thomas0728大大提到的"繼承是一種靜態的關係,無法做到動態而有彈性的變化"我個人覺得不是很同意,如Delphi用上了metaclass,幾乎是完全的動態型別,非常出色的實作方法。不知道"繼承是一種靜態的關係"是指那個部份呢?
thomas0728
中階會員


發表:112
回覆:260
積分:89
註冊:2002-03-12

發送簡訊給我
#11 引用回覆 回覆 發表時間:2004-10-17 16:31:41 IP:61.70.xxx.xxx 未訂閱
很多人以為採 oo 的機制來寫程式,就可以突然間少寫一些程式,事實上這是一個誤會,該寫的該做的一項也少不了,比如說,每個欄位的輸入檢查及前後欄位檢查,事實上這些都是無法避免的,只是寫的地方與方式不太一樣,要思考的方式也不太一樣. OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。 這句話本身是對的,但 metaclass 是 delphi 獨有的語言機制,如果今天要用 c++ 來實作恐怕浱不上用場,所以討論時就不以一種語言特有的機制來討論,比較會有普遍性,況且使用
------
Thomas Chiou
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#12 引用回覆 回覆 發表時間:2004-10-17 16:32:49 IP:61.229.xxx.xxx 未訂閱
個人對於pwipwi版主所說的metaclass,有興趣想多瞭解一點,可否請版主概略述敘一下內容,謝謝!!    
引言: 對於thomas0728大大的文章,我個人有些不同的見解… OO的概念是在高於語言層次的,至於多型實作則是言語本身的問題。比如大家常聽到的Cplusplus多型上的缺點,並不代表那就是OO的多型缺點。其他語言比如smalltalk、Delphi,在這方面做得比Cplusplus更好。 至於thomas0728大大提到的"繼承是一種靜態的關係,無法做到動態而有彈性的變化"我個人覺得不是很同意,如Delphi用上了metaclass,幾乎是完全的動態型別,非常出色的實作方法。不知道"繼承是一種靜態的關係"是指那個部份呢?
hahalin
版主


發表:295
回覆:1698
積分:823
註冊:2002-04-14

發送簡訊給我
#13 引用回覆 回覆 發表時間:2004-10-17 18:31:40 IP:218.170.xxx.xxx 未訂閱
突發奇想 各位覺得不是重點可以省略過去沒關係 我倒是很好奇以設計erp系統為例, 像sap或是oracle的erp都得作到充分且必要得幾乎巨細靡遺全部用OO,design pattern在腦海中大鬥法一翻才開始design嗎? 如有謬誤還請不吝指正...
pwipwi
版主


發表:68
回覆:629
積分:349
註冊:2004-04-08

發送簡訊給我
#14 引用回覆 回覆 發表時間:2004-10-17 20:11:06 IP:140.112.xxx.xxx 未訂閱
關於change.jian大大提到的metaclass方面,我自已也只是"知其然,不知所以然"。不過我記得Inside VCL有深入的提到這個方面的主題,相信李維大師一定有精闢的介紹。另外我之前的拙著VCL property viewer也可以幫助分析metaclass。
thomas0728
中階會員


發表:112
回覆:260
積分:89
註冊:2002-03-12

發送簡訊給我
#15 引用回覆 回覆 發表時間:2004-10-17 20:33:15 IP:61.70.xxx.xxx 未訂閱
metaclass在李維的 高等 DELPHI 程式技術一書有提到,另外在 DELPHI 學習筆記裡也有到,但以上這二本書好像都絶版了,另外美商歐萊禮出的一本書裡也有介紹,書名忘了,不過 METACLASS 只是動態產生類別的機制,不過用 DESIGN PATTERNS 的 FACTORY MENTH 或 ABSTRACT FACTORY 會更好用 如果愛情也有味覺 那麼 有沒有ㄧ種愛 微微泛酸 不太苦澀 有點甜密 嚐起來的滋味讓人想起幸福 Thomas Chiou
------
Thomas Chiou
den3do
一般會員


發表:2
回覆:7
積分:1
註冊:2003-01-15

發送簡訊給我
#16 引用回覆 回覆 發表時間:2004-10-17 21:12:03 IP:220.139.xxx.xxx 未訂閱
學習以 OO 的思考方式來設計程式    看到這句話小的真的有粉大的感觸, 小的在寫一隻程式時,只會想個大略的流程, 然後開始動工,寫著寫著才發現ㄟ, 這個From的Code 好多ㄛ,以後維護一定粉難, 不過管他的,先寫再說(熱血中 or 趕工中), 有天程式ok了,要開始整理程式碼, 才突然發現,有些東東弄成物件會比較好ㄟ, 不過木已成舟, 自己寫好玩的程式當然還可以改寫, 但是如果是公司的程式,沒Bug就菩薩保佑了, 還改寫勒.....  幾次下來,就想好好研究一下所謂的 > ㄞ...
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#17 引用回覆 回覆 發表時間:2004-10-19 21:09:31 IP:61.229.xxx.xxx 未訂閱
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

發送簡訊給我
#18 引用回覆 回覆 發表時間:2004-10-20 16:24:52 IP:61.218.xxx.xxx 未訂閱
自己回應自己; <>< 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

發送簡訊給我
#19 引用回覆 回覆 發表時間:2004-10-21 01:23:20 IP:61.70.xxx.xxx 未訂閱
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 如下

          TControlClass=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 便發揮了功能
不知從以上的程式碼各位是否看出 metaclass 的功 結論就是,根據 metaclass 來動態建立類別及物件時,這些類別的同祖先類別是同一個,物件所要使用的方法的參數也是一致的 學會 metaclass 這樣才是愛台灣與愛 delphi 我就是愛 delphi ,謀你是買安哪 < >< > 如果愛情也有味覺 那麼 有沒有ㄧ種愛 微微泛酸 不太苦澀 有點甜密 嚐起來的滋味讓人想起幸福 Thomas Chiou
------
Thomas Chiou
change.jian
版主


發表:29
回覆:620
積分:439
註冊:2003-06-02

發送簡訊給我
#20 引用回覆 回覆 發表時間:2004-10-21 08:56:45 IP:61.218.xxx.xxx 未訂閱
感謝thomas0728,對於metaClass,我己完全明瞭.    昨天剛好系統裡需要有這樣的功能,在看到online help及DELPHI 學習筆記裡的說明後,已瞭解其用法.並且也在我的系統中實作出來.    做出這個功能,讓我少寫很多的程式碼.在次證明,OO真的不錯用!!
系統時間:2024-07-05 23:27:08
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!