想了解這是何種技巧(關於介面) |
答題得分者是:Coffee
|
alvin26
初階會員 發表:24 回覆:41 積分:28 註冊:2005-04-12 發送簡訊給我 |
|
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
這算是個大哉問,我不熟OOP,只能回個大概。
1. 關於Delphi Win32的Interface(Delphi 7以前),並不是一個純粹的Interface,它的實作最主要是為了要讓Delphi擁有使用Microsoft COM的能力,最上層是IUnknown,你可以找一下IUnknown這個interface在Delphi文件及Micrososft文件裡面的相關內容。當你利用QueryInterface去詢問該instance是否實作了IDOMPersist的時候,它就會回給你一個IDOMPersist的實體,讓你可以有這個interface的function可以呼叫。這是在你無法得知該instance是否實作某個interface時使用的方法,也是COM的主要結構之一。 2. 就一個純粹的Interface來說,Thinking in Java的作者說,你可以想成是一個契約。這個契約約定了使用這個介面的人必須有相同的function prototype,也就是輸出入介面將會相同,而實作則視各類別需要而可以有不一樣的實作,只要達到契約的目的即可。 因此IDOMPersist這個interface約束了所有實作IDOMPersist 正因為interface並沒有實際的實作,因此多重繼承最顯而易見的成員函式衝突的問題就不存在。 如IDOMPersisst有Save();這個函式,我自己也實作另一個ICustomStream,它也要求了Save()這個函式,雖然兩者都要求,但兩個目的是一樣,因此完成了這兩個interface要求的契約。 3. 就基礎來說,物件導向的程式語言本來就鼓勵使用抽象層類別(不一定是要interface),透過操作抽象層類別或介面來達到統一問題處理流程,又讓下層的實作可以各自保有各自必要的特性。 如你舉的例,實作IDOMPersist的save實際上只是個空殼,當我呼叫save的時候,XML的類別可以去實作將內部xml資料存成xml檔,HTML的類別可以將資料存成html檔。 在Delphi最容易找的例子就是在dpr檔內找到Application.CreateForm,它傳入的參數是TApplication.CreateForm(InstanceClass: TComponentClass; var Reference); 不管我實作的Form的類別叫什麼樣子,它的class的上層都有一個TComponentClass,而它內部確保實作TComponent,從而確保當我在呼叫CreateForm的時候可以正確的被初始化。而DataModule上層也正是一個TComponent,所以當你選擇在程式開始時就初始化DataModule時,Application.CreateForm也能正確的初始化DataModule。 在Java最常舉的例子是排序,一個自訂類別當它需要可以被排序時,它必須去實作IComparable(在C#也是同一個interface name),好讓其它使用到排序的類別知道如何去對這個自訂類別使用CompareTo去排序。 在某些狀況下,也會有沒有明顯的實作IComparable介面,而是單純的提供CompareTo函式的狀況發生,這時候為了測試以及確保該類別真的有提供此函式而且可以被排序,Reflection與RTTI就因此產生了。(當然從這邊可以再衍生出一點wrapper的味道出來) 4. 回到系統/架構面來說,以上層/抽象類別的操作來統一所有的動作為基礎的,有一個觀念叫作控制反轉(IoC),你可以參考這個連結並看看其它有資料:http://www.javaworld.com.tw/confluence/pages/viewpage.action?pageId=1857 我能理解的大概就是這樣,如有錯誤煩請不吝指教。
------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。 為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。 在引述到我的文時自然會儘量替各位想辦法,謝謝大家!
編輯記錄
Coffee 重新編輯於 2012-03-21 05:12:23, 註解 無‧
|
alvin26
初階會員 發表:24 回覆:41 積分:28 註冊:2005-04-12 發送簡訊給我 |
|
Coffee
版主 發表:31 回覆:878 積分:561 註冊:2006-11-15 發送簡訊給我 |
因為沒有人吐我槽,我自己來吐自己。
利用QueryInterface取得的是Reference(參考),這件事就COM的架構來說也很重要。對於COM object的生命週期是取決於Reference count(某些JVM GC實作機制也是類似的方式),當利用QueryInterface取得Reference時,該COM object的ref count會 1,所以在使用完此參考後必須使用Release來對ref count -1,當COM object的ref count用盡時,該object就會被回收。而Reference並不是實體,真正的instance還是原本的COM object。 太久沒寫都忘的差不多,應該還有很多強者可以吐我槽才對。
------
不論是否我發的文,在能力範圍皆很樂意為大家回答問題。 為了補我的能力不足之處,以及讓答案可以被重複的使用,希望大家能儘量以公開的方式問問題。 在引述到我的文時自然會儘量替各位想辦法,謝謝大家!
編輯記錄
Coffee 重新編輯於 2012-03-23 02:15:25, 註解 無‧
|
P.D.
版主 發表:603 回覆:4038 積分:3874 註冊:2006-10-31 發送簡訊給我 |
Coffee 兄, 我都看不懂你們在談什麼, 怎麼敢吐糟呢?
===================引 用 Coffee 文 章=================== 因為沒有人吐我槽,我自己來吐自己。 利用QueryInterface取得的是Reference(參考),這件事就COM的架構來說也很重要。對於COM object的生命週期是取決於Reference count(某些JVM GC實作機制也是類似的方式),當利用QueryInterface取得Reference時,該COM object的ref count會 1,所以在使用完此參考後必須使用Release來對ref count -1,當COM object的ref count用盡時,該object就會被回收。而Reference並不是實體,真正的instance還是原本的COM object。 太久沒寫都忘的差不多,應該還有很多強者可以吐我槽才對。 |
leveon
資深會員 發表:30 回覆:389 積分:303 註冊:2012-02-12 發送簡訊給我 |
寫個範例大家就能瞭解基本原理
type IMyInterface = interface ['{D4BBAE4C-CCE1-4790-A329-7DFBD85C8EE4}'] procedure P1; end; TForm1 = class(TForm,IMyInterface) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } procedure P1; public { Public declarations } end; //Form 1上 P1 方法 procedure TForm1.P1; begin showmessage('From Form1'); end; //透過Interface 呼叫P1 procedure TForm1.Button1Click(Sender: TObject); const { Library ID } LibraryUID :TGuid = '{D4BBAE4C-CCE1-4790-A329-7DFBD85C8EE4}'; var MyIntf:IMyInterface; begin // QueryInterface Form1.QueryInterface(LibraryUID,MyIntf); MyIntf.P1; MyIntf:=nil; //這樣也行 (Application.FindComponent('Form1') as IMyInterface).QueryInterface(LibraryUID,MyIntf); MyIntf.P1; MyIntf:=nil; end;優點: 1.減少 unit 互相uses 2.更好的封裝 缺點: 架構不確定時 容易規劃不當 程式更迂迴
編輯記錄
leveon 重新編輯於 2012-06-02 00:54:31, 註解 無‧
|
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |