線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2508
推到 Plurk!
推到 Facebook!

淺談策略模式 - 使用 Delphi + Interface

 
GrandRURU
站務副站長


發表:234
回覆:1654
積分:1752
註冊:2005-06-21

發送簡訊給我
#1 引用回覆 回覆 發表時間:2014-09-01 17:24:51 IP:59.120.xxx.xxx 訂閱

淺談策略模式 - 使用 Delphi Interface



Delphi 這麼久,Class 一直都是我愛用的關鍵字之一。
在看了 Code in Delphi 之後,還是不了解為什麼要使用 Interface
於是又看了下 Head First Design Patterns (深入淺出設計模式) 的第一章。
按照我現在只會的物件導向概念,在鴨子類別及實體的設計,大概會長成這樣:

於是,如果有 100 種鴨子物種,我就必須 override Display, Fly, Quack 這三個函式。
這實在很蠢!
那麼,撇開 Display 這個非重寫不可的因子,將 Fly, Quack 獨立開來設計如何呢?
Quack 為例,大概會長成這樣:
嗯……如果有 1000 種叫聲,還是要實作 1000 種叫聲的類別,使用 Interface 好處在哪呢?
我想應該是在最終設計上可以不用實做全部的個別行為函式吧。
實作成品如下圖:

範例程式:下載
編輯記錄
GrandRURU 重新編輯於 2014-09-01 17:41:48, 註解 無‧
sryang
尊榮會員


發表:38
回覆:742
積分:876
註冊:2002-06-27

發送簡訊給我
#2 引用回覆 回覆 發表時間:2014-09-02 08:13:33 IP:59.127.xxx.xxx 未訂閱
飛機會飛,鳥會飛,熱氣球也會飛
那麼「飛」這個行爲你要定義在哪裡呢?
定義一個「飛行物」interface
實做這個 interface 就有「飛」這個行爲不是更明瞭?
------
歡迎參訪 "腦殘賤貓的備忘錄" http://maolaoda.blogspot.com/
GrandRURU
站務副站長


發表:234
回覆:1654
積分:1752
註冊:2005-06-21

發送簡訊給我
#3 引用回覆 回覆 發表時間:2014-09-02 09:14:21 IP:59.120.xxx.xxx 訂閱
目前我是使用 virtual (+) abstract function 來實作

現在看到 Interface 可以做類似 IA IB 的合併處理,但還是省不了同時實作的痛苦

比方說:
interface I上飛; 實作 T上飛
Interface I右飛; 實作 T右飛

現在我要寫一個「右上飛」
就變成:
interface 右上飛(I上飛 I右飛); 實作 T右上飛

然後自行 Copy T上飛 和 T右飛 的實作內容後再貼到 T右上飛

這樣的工法好像並沒有省到 Coding 的時間。

還是我哪邊想的不對?

===================引 用 sryang 文 章===================
飛機會飛,鳥會飛,熱氣球也會飛
那麼「飛」這個行爲你要定義在哪裡呢?
定義一個「飛行物」interface
實做這個 interface 就有「飛」這個行爲不是更明瞭?
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2014-09-02 18:16:00 IP:114.32.xxx.xxx 訂閱
我有幾個好多年以上的模式(Design Pattern)經驗分享補充如下:
1/ 模式的好處不單純「只是為了讓code寫的更少」,這只是其中的一個可能好處。
2/ 模式可以讓維護的時間縮短,比如,讓錯出可能性變少,若要加入新功能時可能快速入手…等等等…
3/ 以ruru的這篇文來看,它與interface可以說沒啥關係。範例中的實作只是為了一個模式的「基本」概念 -- 「is a」與「has a」的解說例子。將一些功能不以繼承的方式,而改由成員來引入物件(如ruru寫的fly的這個物件),經常是很重要的,ruru已經有說明了…override的問題。
4/ interface(我這詞特指delphi 關鍵字interface,或是java 關鍵字interface) 的存在價值是因為「多重繼承的需求」,所以要探討為何一定要使用interface,就要講多重的需求。我以下圖來和大家說明精華:



問題: 以上是一個單根繼承的圖。請假想一個問題,如果class12突然需要一個fly的功能,而class14也有fly的功能需求。這時候,如果寫class12與class14的程式人員不同,很可能他們會各自實作自己的,有點像又不太像 (請看圖有底線的)。這時候fly就變得很不統一,維護上或是未來的整合上都容易出問題。於是你會說:

那我們把這個fly搬到遠遠的class3,那麼fly的功能就"統一"了,不會各寫各的。但…… 這一搞,是否影響到許多可能不需要的class? 若整個繼承圖是很深層的、廣的,"無辜"的class就很多(他們沒那需要啊)。若這時候能夠多重繼承就好了…

於是若可以有一個class,那定義了fly的許多方法,然後在class12與class14上被繼承,那問題不就搞定? 很好! 但,delphi,java就是不想要多重繼承 (原因容我後述),於是就開了一個洞,搞一個叫interface的關鍵字,然後讓class可以繼承父類外的額外interface。至此,你應該可以了解為什麼需要interface。

delphi與java為何不想要如c 一樣可以多重承(注意,我這裡講的是c 的多重繼承,而非概念性的多重繼承)? c 裡的多重繼承是真的可以把每個class的「成員」與「函式成員」通通都繼承下來的,且函式也不一定要是虛的(vitual)。c 這個多重繼承是複雜但能力極強的功能。關鍵在「成員data member」可以被繼承,delphi/java的interface是不可以有data member。因原是一堆data被繼承後,會有重複的可能並造成問題,雖然c 有方法可以避開這問題,但還是不易被一般人搞定。

所以,delphi/java的interface,「只可以定義方法」,為的就是了讓複雜度變低。 interface 其實就是多重繼承(指概念性的,不是特指c 的),它讓class可以引入很多的介面。但inteface又不要有data member重複的負擔。就好像你要有牛奶的營養,但又不想要有脂肪。inteface就是無脂奶。c 的多重繼承則是可自己調配要低脂或無脂或全脂。

下一個inteface(delphi/java)的重點結論:
1/ 它是為了「統一介面(定義)」而讓「維護上」(非code寫少,若要寫少一開始就class就好),「整合上」有很大的益處,尤其是多人實作的大型案子。
2/ inteface就是一種「c 多繼承的特化」,也算是有多重繼承的能力,只是不能繼承data…

題外補充abstact class (指JAVA/DELPHID的關鍵字)
若只「簡單」單根的需求,有沒有必要一定要interface? 當然可以不用。abstract class 與inteface都有一個特色,就是繼承後,一定要實作。不能立刻拿來變成物件(delphi可以過,但compiler會warnning)。但abstract可以有data member。所以,繼承一個abstract class可以讓程式碼少寫一點(因為data member或是一些非abstract方法的都可以被繼承下來),只要實作abstract class中的abstract function。若你只是繼承inteface,那子類就要實作inteface的方法,並加入自己要的方法或成員。

若你只是想要code寫少,那… 一開始就普通的class就好,就別搞abstract class 或是 interface,這樣寫最少。然後普通的class再繼承普通的class… 但,這只適合一個人寫作,且案子很小,想要快速開發模型等。

最後請注意「用詞」: inteferface,abstract,多重繼承(multiple inheritance),可能是「概念性的詞」或是指某語言的「關鍵字」。討論時要注意,以免沒共識。比如說,inteface的概念性說詞,可能指的是base class,也就是base class定了一些虛方法,然後讓子類依照定的去override,但並不是說base class裡不能有data member,所以這個interface是概念性的說法,強調的是使用物件導向中的「多面性」。

希望這篇能幫助一些需要的人,因我花了好幾年以上的內力思考而得的精簡說明。但然,也不保證100%都正確,歡迎指教!
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2014-09-02 18:28:54 IP:114.32.xxx.xxx 訂閱
再補一下: ruru的例子就是一個說明「interface概念 + has a」的例子。注意! 注意!  此inteface是概念詞,與 java/ delphi的 interface的用意,關連不大!  
所謂的inteface的概念就是指ruru把 fly變成一個 base class (僅管它用的是interface的關鍵字,但實值上若改abstract或是一般的class字都可以),接著利用這個「定義好的介面」來設成鴨子的成員,並使用「多面性」讓呼叫base class的funtion但可以叫出不同的行為。

以上,是「定義父類」讓「子類照作」經「多面性」達成鬆散結合的任務。 而把fly的功能引入鴨的成員,就是一種 「has a」的做法。而不是讓鴨去繼承fly。


但,以上通通不是 delphi java interface關鍵字存在的用意!!!
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
pcplayer99
尊榮會員


發表:142
回覆:740
積分:591
註冊:2003-01-21

發送簡訊給我
#6 引用回覆 回覆 發表時間:2014-10-08 11:01:28 IP:183.14.xxx.xxx 訂閱
inteferface 在 Delphi 里面非常好用。至于设计模式,我觉得只是给人参考的,不必拘泥。所谓模式,即非模式,是名模式。

我列举几个用 Interface 的理由:

1. 实际写代码时,不可能一开始就设计周全,因此一个 Class 不可能一开始就事先想好了抽象的父类该有哪些方法,后面的子类该有哪些方法。代码写到后面,一定会发现有些东西需要改。这时候如果你改了父类,后面一大堆子类都要跟着改,问题就大了。如果采用 Interface,你只改某个 Interface,涉及到的类也只是使用了这个 Interface的类。如果这个interface涉及到的类实在很多,那你干脆新起一个 Interface 好了。反正一个类可以实现多个不同的 Interface。

2. 不管什么模式,代码的【架构】的最大目的是当代码非常多的时候,如何管理代码。所谓的类,也就是把一类的代码,封装到一个Class里面。代码的合理组织方式应该类似军队。几个人,可以凑成一个班;几个班,凑成一个排;几个排,凑成一个连。这样逐层封装,到了顶上,实现功能时就不用关心底下的代码实现细节。要把这些 Class 组合在一起,采用 Interface 会更为方便。比如一个连底下有一个炊事班负责做饭。如果搞类继承,连显然不能从炊事班继承下来。如果搞Interface,连就可以有一个炊事班实现的做饭的Interface,但连这个Class不需要再把这个Interface的代码复制一遍,只需要用 DELPHI 的语法关键词直接将这个Interface的实现指向它底下的炊事班就好了,也是可以少写代码的。

3. 物件的生命周期管理。利用 DELPHI 对Interface的引用计数的功能,很容易做到对Object的生命周期管理。我自己写了一个OBJECT POOL,类似JAVA或C#的自动垃圾回收,只用了不到200行代码。在我的一个有几十万行代码的程序里面,工作得非常好。没用这个之前,因为代码太复杂 ,总会有OBJECT该FREE而没有FREE导致的内存泄漏。
系統時間:2017-11-20 12:01:43
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!