Delphi物件導向 繼承與封裝

2021-04-30 09:51:11 字數 2948 閱讀 7748

delphi物件導向學習隨筆四:繼承與封裝

在討論類的封裝前,我想先說說「繼承」和「包含」的區別。

繼承(是乙個(is a ...)):

我在看很多資料的時候,講到類的繼承時,很多資料都會提到:「選乙個合適的類做為新類的父類可以有效的提高**的重用程度,從而減少很多重複的工作量。」

的確,上面的話很有道理,合理的選擇父類是可以減少重複的工作,但是,這裡存在乙個邏輯性的問題:即、新的子類「是乙個(種)」父類,這麼說或許有些繞口,舉個例子:例如動物類是生物類的子類,那麼我們也可以這樣說:「動物是一種生物。」這樣說,顯然在邏輯上並沒有矛盾的地方。

那麼,我們來看下乙個例子:(注意上下兩個例子中指定的父類)  

**:type

temployee = class(tstrings)

...public

property employeename: string ...; //員工姓名

property employeeage: word ...;    //年齡

....

property strings.....;             //考勤記錄

end;這是我曾經看過的乙個類,描述一員工的資訊的,包括其考勤記錄。首先這個類是沒有語法和語義錯誤的,而且工作起來也正常,但是它在「繼承」這個邏輯概念上卻有問題,那就是「員工/職員 是 乙個列表,」這樣說顯然不合情理。

我曾經問過作者這樣設計的意圖,他回答只是「這樣簡單,可以執行就得了,管那麼多做什麼?」但是,我認為,這樣是錯誤的,因為在邏輯上說不通。

包含(有乙個(has a ...))

包含其實就是指乙個類包含另乙個類的例項,比如delphi中的tcombobox的items屬性。

上面的類,我們可以這樣改:  

**:type

temployee = class(tobject)

...public

property employeename: string ...;

...property attendances: tstrings ...; //考勤記錄

end;這樣看看是不是好多了呢,而且在邏輯上就從「員工是乙個列表」變成了「員工有乙個考勤列表」。

類的封裝:

在決定編寫乙個新類前,我們首先應該仔細考慮這個類是用來幹嗎的,而不是興奮的開始寫**。乙個良好的類的介面(屬性或方法,和inte***ce是兩個概念,以下統稱介面,懶得打那麼多字,^_^ 或許後面會說inte***ce的概念)應該是具有一致性的。

假如有乙個類,他的一部分介面用來操作堆疊,一部分介面用來從資料庫中提取資料,還有一部分介面用來控制列印走紙,那麼,這個類看上去真的比較亂,因為使用者不知道你這個類到底是為什麼編寫的,這樣的類也就不能稱之為類了。看上去更像是把一堆風馬牛不相及的函式死拉硬拽到一起「湊份子」湊出來的「累」。

乙個封裝良好的類,應該有乙個一致性的介面,也就是說,類提供給外界使用的所有介面都應該是有關聯的,上面的類其實我們可以寫成三個模擬較好:乙個類用來運算元據庫、乙個類用來操作堆疊、乙個類用來控制印表機走紙。

這樣設計的好處是能讓人一看就清楚的知道,你這個類到底是圍繞什麼來工作的,就像我們寫作文也必須有乙個中心思想一樣,如果沒有中心思想,那麼這篇作文也就不叫作文了,而是流水帳了。

另外,友情提示一下,在任何時候,都不要有「寫乙個萬能類」的想法。

隱藏資訊:

在編寫類的時候,我們應該非常清楚的知道,這個類有哪些資訊是不需要外界訪問的,就像司機開汽車,司機只需要知道怎麼弄方向盤,怎麼踩離合器,怎麼剎車和提速就可以了。而有關汽車內部發動機的工作原理,司機並不需要知道。

當我們在拿到乙個類的code的時候,除非你是為了學習,否則你應該忍住看私有域所有實現**的衝動。雖然現在提倡開源,但是我想開源的目的是為了提高相互交流,而並不是為了讓你可以把原本私有的、外界無法訪問的介面對外開放。如果你把原先外界無法訪問的域資訊全部對外公開了,那麼你這個類存在就無任何意義了。

屬性:類與類之間傳遞資料,我推薦使用屬性property而不是直接用變數來傳遞。

例如:tcontrol類的left、top、width、height四個屬性,如果它是以變數的方式來提供給外部直接使用的話,我們設想一下乙個這樣的需求:假如我們要改變一下元件寬度,並且改變寬度後要在元件最右邊繪製一張位圖,那麼當外界改變了元件寬度時,由於這個變數是直接供外界讀寫的,它在被寫而發生改變的時候,元件無法得到通知,因此也就無法實現重畫點陣圖的需求了。

而在屬性定義的時候,你必須指定乙個read限定符和乙個write限定符(read 或 write 都可選但你至少必須指定乙個限定符),當你為乙個屬性的write限定符指定了乙個方法(delphi中必須是乙個過程)時,當你執行如:tcontrol.width:= 0;這樣的**時,編譯器會自動為你呼叫write指定的方法,這樣我們就可以在屬性發生改變的時候讓類去執行一些有關的操作,換言之就是類可以得到屬性值被修改的通知而做出相應的動作。

同樣,當我們需要讓外部訪問類中私有部分的乙個變數但不允許改動的時候,我們可以為類新增乙個屬性,並只指定read限定符來指向這個變數,不用write限定符,從而限制為唯讀。

其他:我們在工作中,往往接到的需求是乙個複雜的龐大的問題,而我們首先要做的就是分解這個問題,把乙個大的問題分解成若干個小的問題,並把他抽象的提取出來,這就是我們類功能的雛形。

舉個簡單的例子,比如工程師建房子,房子有一層的小平房,有一百層大廈,但是我們可以換個角度去看這個問題:不管你建多少層樓,房子都是由x個房間組成的,區別只在於房間數量的不同而已。這就是他們的共性。

這裡,再說一句,接到乙個新的專案以後,第一件事不是立即興奮的開始寫**,而是首先要做規劃。

繼續拿做房子來說(-_-|)任何乙個工程師,在接到新的工程的時候,應該不會有任何乙個人會先考慮怎麼砌磚吧。或許你會因為專案小而放棄準備期,但是我想說一下,專案不分大小,準備工作是必不可少的。

曾經我聽過乙個小笑話:說有乙個人,做乙個鳥籠子,由於他只看過一次鳥籠子,而在他開始做之前又沒有去實際的看過籠子的成品,而導致他的鳥籠做完後,竟然發現他犯了乙個最離譜的錯誤——籠子上沒有門。

這個小笑話其實也說明了預先的準備工作的重要性了。

javascript 物件導向封裝與繼承

整理一下js物件導向中的封裝和繼承。1.封裝 js中封裝有很多種實現方式,這裡列出常用的幾種。1.1 原始模式生成物件 直接將我們的成員寫入物件中,用函式返回。缺點 很難看出是乙個模式出來的例項。複製 如下 function stu name,score var stu1 stu 張三 80 var...

物件導向之封裝與繼承

基本資料型別傳遞數值 引用資料型別傳遞的是位址。常量池 儲存資料的時候,先便利本記憶體中是否包含即將要儲存的資料,如果包含,則不重新開闢空間,如果不包含,開闢新的空間儲存。private 只允許本類使用,其他類看不到 封裝 給屬性賦值的時候增加限制 將屬性新增private,只允許本類使用此屬性 將...

物件導向(封裝 繼承)

1.類的訪問修飾符有public private internal protected。其中pubulc 公共的,只要引用了命名空間,就可以隨意進行訪問 private 私有的,只有當前類內部才可以訪問 internal 內部的,當前程式集內可以訪問,程式集就是命名空間,此修飾符是預設的 prote...