0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》——什么是類?

UtFs_Zlgmcu7890 ? 來源:未知 ? 作者:佚名 ? 2017-10-10 10:52 ? 次閱讀

近日周立功教授公開了數(shù)年的心血之作《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》,電子版已無償性分享到電子工程師與高校群體下載,經(jīng)周立功教授授權(quán),特對本書內(nèi)容進(jìn)行連載。

>>>>1.1類與對象

亞里士多德可能是第一個(gè)研究類型概念的人,他提到了“魚類和鳥類”。將具有共同的行為和特征的所有對象歸為一個(gè)類的思想,在第一個(gè)面向?qū)ο笳Z言Simula-67中得到了直接應(yīng)用,其目的是為了解決模擬問題。比如,銀行的出納業(yè)務(wù),包括出納部門、顧客、業(yè)務(wù)、貨幣的單位等大量的對象,將具有相同數(shù)據(jù)結(jié)構(gòu)(屬性)和行為(操作)的對象歸在一起為一個(gè)類,屬于類的任何對象都共享該類的所有屬性,這就是類的來源。

創(chuàng)建抽象數(shù)據(jù)類型是OOP的基本思想,幾乎能象完全內(nèi)建類型一樣使用。程序員可以創(chuàng)建類型的變量和操作這些變量。每個(gè)類的成員都有共,每個(gè)賬戶有余額,每個(gè)出納員都能接收存款等。同時(shí)每個(gè)成員都有自己的狀態(tài),每個(gè)賬戶有不同的余額,每個(gè)出納員都有名字。通常在計(jì)算機(jī)中出納員、客戶、賬戶和交易等都被描述為唯一的實(shí)體,這個(gè)實(shí)體就是對象,每個(gè)對象都屬于一個(gè)定義了它的行為和特性的特定類。

由此可見,類和類的對象不是相同的概念,與圖紙和建筑的關(guān)系類似,對象的描述依賴描述它的類。因此可以通過創(chuàng)建類的實(shí)例創(chuàng)建對象,即定義類的變量,這個(gè)過程叫做實(shí)例化。

>>>1.1.1 對象

從人類認(rèn)知的抽象角度來看,對象可以是下列事物之一:

● 一個(gè)可以觸摸或可以看見的東西;

● 在智力上可以理解的東西;

● 可以指導(dǎo)思考或行動的東西。

顯而易見,一個(gè)對象反映了某一部分的真實(shí)存在,因此對象是在時(shí)間和空間中存在的某種東西。軟件中的“對象”術(shù)語首先出現(xiàn)在Simula語言中,對象存在于Simula程序中,用于模擬現(xiàn)實(shí)世界的某個(gè)方面。

某些對象可能有明確的概念邊界,但代表的是不可觸摸的事件或過程。比如,一個(gè)立方體和一個(gè)球相交,它們的相交線是一條不規(guī)則的曲線。雖然它離開了球體或立方體就不存在了,但這條線仍然是一個(gè)對象,因?yàn)樗忻鞔_定義的概念邊界。

某些對象可能是可觸摸的,但物理邊界不太清晰。比如,河流、霧和人群等就屬于這種類型的對象。雖然類似于美和色彩這樣的屬性不是對象,愛和恨這樣的感情也不是對象,但這些東西有可能成為其它對象的屬性,比如,一個(gè)男人(一個(gè)對象)愛他的妻子(另一個(gè)對象),或者說某只貓(又一個(gè)對象)是灰色的。由此可見,屬性表示對象記憶的信息,且只能通過對象的操作來訪問和修改。

當(dāng)傳統(tǒng)的過程模塊或函數(shù)返回調(diào)用者時(shí),不會帶來任何副作用,模塊運(yùn)行結(jié)束,只將其結(jié)果返回。當(dāng)同一模塊再次被調(diào)用時(shí),就象是第一次誕生一樣。模塊對以前的存在沒有任何記憶,就象人類一樣對以前的存在一無所知。

就對象而言,對象的一個(gè)重要特征是它們充當(dāng)數(shù)據(jù)的容器,因此對象具有記憶功能,對象知道它的過去,通常也將包含在對象屬性中的數(shù)據(jù)值稱為對象的狀態(tài)。當(dāng)一個(gè)對象的調(diào)用者給該對象一個(gè)信息后,如果該調(diào)用者或其它調(diào)用者要求該對象再次提供這一信息,則該對象執(zhí)行結(jié)束后并沒有死,因此對象具有如何保持其狀態(tài)(狀態(tài)即對象擁有值的集合)的能力。

假設(shè)你在看一個(gè)人,肯定會將這個(gè)人當(dāng)作一個(gè)對象。顯然,每個(gè)人都有數(shù)據(jù),比如,name、birthdate和weight等;一個(gè)人還有行為,比如,走路、說話和呼吸等,因此可以說對象是由“數(shù)據(jù)和行為”構(gòu)成的。在現(xiàn)實(shí)世界里,由于每個(gè)對象的狀態(tài)不一樣,因此可以用存儲在一個(gè)對象中的數(shù)據(jù)表示對象的狀態(tài),數(shù)據(jù)包含了能夠區(qū)分不同對象的信息。

在OO程序設(shè)計(jì)中,每個(gè)對象都有唯一的標(biāo)識,標(biāo)識是一個(gè)對象的屬性,用于區(qū)分這個(gè)對象與其它所有對象。而這個(gè)唯一的標(biāo)識可以通過句柄機(jī)制提供,因此可以借助這個(gè)句柄引用對象。不同的語言實(shí)現(xiàn)句柄的方式不一樣,比如,地址、數(shù)組下標(biāo)或人為編號。

在現(xiàn)實(shí)世界中一些對象有對等物,比如,ZLG公司,另一些對象則是概念實(shí)體,比如,解一元一次方程,還有一些其它的對象,比如,棧、數(shù)組變量名a,都是為了實(shí)現(xiàn)而引入的,沒有對應(yīng)的物理實(shí)體。

許多開發(fā)人員可能會認(rèn)為“一個(gè)包含了另一個(gè)對象的對象”,其本質(zhì)上與“一個(gè)具有純數(shù)據(jù)成員的對象”是完全不同的,但是那些看起來不是對象的數(shù)據(jù)成員實(shí)際上也是對象,比如,整數(shù)和雙精度數(shù)。在真正的面向?qū)ο笳Z言中,萬事萬物都是對象,甚至內(nèi)置數(shù)據(jù)也是對象,即使其行為只是運(yùn)算。

由此可見,雖然對象是具有明確定義的邊界的東西,但還不足以區(qū)分不同的對象。因?yàn)橥粋€(gè)類的每個(gè)對象具有不同的句柄,在任何特定時(shí)刻,每個(gè)對象可能有不同的狀態(tài)(指存儲在變量中的不同的“值”),因此對象是一個(gè)具有狀態(tài)、行為和標(biāo)識的實(shí)體。

對象又分持久對象和主動對象,持久對象是指生存期可以超越程序的執(zhí)行時(shí)間,而長期存在的且所有的操作都是被動執(zhí)行的對象。在主動對象概念出現(xiàn)之前,人們所理解的對象概念只是被動對象,即對象的每個(gè)操作都是被動地響應(yīng)從外部發(fā)來的消息才可以執(zhí)行。

在開發(fā)一個(gè)具有多任務(wù)并發(fā)執(zhí)行的系統(tǒng)時(shí),如果僅有被動對象的概念,則很難描述系統(tǒng)中的多個(gè)任務(wù)。其實(shí)并發(fā)不僅僅存在操作系統(tǒng)中,如今多個(gè)任務(wù)并發(fā)可以說無處不在。每個(gè)任務(wù)在實(shí)現(xiàn)時(shí)應(yīng)該成為一個(gè)可以并發(fā)執(zhí)行的主動程序單位,那么如何描述呢?

如果用被動對象將無法描述那些不接收任何消息也要主動工作的對象,比如,交通燈控制系統(tǒng)中的信號燈,溫控器中的傳感器,它們的行為都是主動發(fā)起的,即主動對象至少有一個(gè)操作不需要接收消息就就能主動執(zhí)行的對象。

盡管發(fā)現(xiàn)對象的活動是從具體事物出發(fā)分析和認(rèn)識問題的,但人們在進(jìn)行這種活動時(shí)實(shí)際上并不局限于對個(gè)別事物的認(rèn)識,而是尋找一類事物的共同特征,將對象抽象為類。

>>>1.1.2 類

類的概念早在柏拉圖之前就出現(xiàn)了,面向?qū)ο?a href="http://www.ttokpm.com/v/tag/1315/" target="_blank">編程就像柏拉圖之后的西方哲學(xué)家一樣延續(xù)了這種思維。類的概念與對象的概念是緊密交織在一起,因?yàn)樵谟懻撘粋€(gè)對象時(shí)不得不提到它的類,但是這兩個(gè)術(shù)語又存在重要的差別。對象是存在于時(shí)間和空間中的具體實(shí)體,而類僅代表一種抽象,因此可以說Validator類代表了所有校驗(yàn)器的共同特征。要確定這個(gè)類中的某個(gè)具體的校驗(yàn)器,則必須說“范圍值校驗(yàn)器”或“奇偶校驗(yàn)器”。

在面向?qū)ο蠓治雠c設(shè)計(jì)的上下文中,將類定義為——類是對現(xiàn)實(shí)世界中事物的描述,類描述了擁有相同屬性、行為和關(guān)系類別的一組對象,一個(gè)對象就是類的一個(gè)實(shí)例,因此沒有共同的屬性和行為的對象不能劃分為一個(gè)類。比如,一個(gè)相當(dāng)高層的抽象,一個(gè)GUI框架,一個(gè)數(shù)據(jù)庫和整個(gè)系統(tǒng)在概念上都是獨(dú)立的對象,因此不能將它們表示為一個(gè)單獨(dú)的類。相反應(yīng)該將這些抽象表示為一組類,通過這些類的實(shí)例互相協(xié)作,提供我們期望的功能。

通常將這樣的一組類稱為一個(gè)組件,而組件是預(yù)先創(chuàng)建好的程序模塊,可與其它模塊一起構(gòu)成一個(gè)程序。通常組件以二進(jìn)制形式發(fā)布,其實(shí)現(xiàn)對使用者來說是隱藏的。如果組件設(shè)計(jì)良好,使用者甚至不需要知道這個(gè)組件使用什么語言編寫的。但組件必須至少暴露一個(gè)接口才能使用,通常組件會有暴露多個(gè)接口。從使用者的角度來看,一個(gè)組件是一些前端接口的后端服務(wù)者,程序員通過組件接口所暴露的函數(shù)操作該組件。由此可見,組件擴(kuò)展了面向?qū)ο笾袑ο笞鳛榉?wù)提供者通過高層接口提供服務(wù)的概念。

在現(xiàn)實(shí)世界里,餅干也是對象,必須先有模子(類),才能做出你想要的形狀的餅干,因此可以認(rèn)為類是對象的模板。比如,只有符合一定條件的數(shù)值才能push到棧中,那么Validator校驗(yàn)器類就是由RangeValidator范圍值校驗(yàn)器、OddEvenValidator奇偶校驗(yàn)器類和PrimerValidator質(zhì)數(shù)校驗(yàn)器類等具體校驗(yàn)器類的對象構(gòu)成的一個(gè)集合體。屬于類的任何對象都共享該類的所有屬性,比如,所有的具體校驗(yàn)器都有這樣的屬性——校驗(yàn)參數(shù)。

在OO程序設(shè)計(jì)中,一個(gè)類就是一種抽象數(shù)據(jù)類型,用戶也可以創(chuàng)建一個(gè)自己的類,而且可以將這個(gè)類當(dāng)做數(shù)據(jù)類型使用。一旦有了類,就可以象使用普通的數(shù)據(jù)類型那樣用類定義變量,如果定義了RangeValidator類,即可用它定義變量rangeValidator。RangeValidator類的變量rangeValidator可以擁有成員變量或域,代表不同校驗(yàn)器的屬性或特性,通常將這些成員變量稱為數(shù)據(jù)成員。

(1)值和屬性

值是一段數(shù)據(jù),屬性描述了類的每個(gè)對象都擁有的一個(gè)值,可以這樣類比——對象之于類如同值之于屬性。比如,name、birthdate和weight都是Person對象的屬性,color、modelYear和weight都是Car對象的屬性。對于每個(gè)對象,每個(gè)屬性都有一個(gè)值,比如,對象ZhangSan的屬性birthdate的值是“21 October 1983”,也就是說,ZhangSan生于1983年10月21日。對于一個(gè)特定的屬性,不同的對象可能會有相同或不同的取值。在一個(gè)類中,雖然每個(gè)屬性的名字都是唯一的,但在所有的類中不一定是唯一的,比如,類Person和類Car都可能有一個(gè)名為weight的屬性。

下面將介紹一種通過屬性詳細(xì)描述類的UML建模語言,一種用于可視化表示、指定、構(gòu)造和描述軟件密集系統(tǒng)中部件的圖形化語言,它提供了一種以圖形化方式表示和管理面向?qū)ο筌浖到y(tǒng)的方法。其不僅是系統(tǒng)設(shè)計(jì)的表示,而且是一種有助于完成系統(tǒng)設(shè)計(jì)的工具。類圖定義了3個(gè)不同的部分,即類名、屬性和方法,用于解釋所構(gòu)建的類。當(dāng)用UML創(chuàng)建對象模型時(shí),盡可能不要在類圖中包含太多的信息,這樣就能集中注意力于整體設(shè)計(jì),而不會將重點(diǎn)放在細(xì)節(jié)上。

圖 4.1所示展示了類建模表示法,顯示了一個(gè)類(左圖)和它所描述的對象(右圖),對象ZhangSan和LiMing都是類Person的實(shí)例。對象的UML表示法是一個(gè)方框,方框里面是對象名后加冒號和類名,對象名和類名都有下劃線,并約定用黑體字表示對象名和類名。類的UML表示法也是一個(gè)方框,也約定用黑體字表示類名,將名字放在方框的正中央,首字符大寫,且用單數(shù)名詞表示類名。類Person有屬性name和birthdate,name是string(字符串),birthdate是date(日期)。類Person中一個(gè)對象的名字取值是"Zhang San",生日取值是“21 October 1983”;另一個(gè)對象的名字取值是"Li Ming",生日取值是“16 March 1950”。

圖 4.1 屬性和值的UML表示法

UML表示法會在框的第二格里列舉屬性,每個(gè)屬性后面都可以有可選項(xiàng),比如,類型和默認(rèn)值。在類之前有一個(gè)冒號,在默認(rèn)值之前有一個(gè)等號。約定以常規(guī)字體顯示屬性名,方框中的名稱左對齊,首字母使用小寫。在對象方框的第二格里,也可能會包含屬性值,其表示法是列出每個(gè)屬性名,之后跟著等號和取值,同樣屬性值也是左對齊,使用常規(guī)字體。雖然有些實(shí)現(xiàn)要求對象有唯一的標(biāo)識符,但這些標(biāo)識符在類模型中是隱含的,即不需要也不應(yīng)該顯式地將它們列舉出來,比如,PersonID:ID。因?yàn)榇蠖鄶?shù)OO開發(fā)語言會自動生成標(biāo)識符,可以使用這些標(biāo)識符來引用對象;反之,則可能需要顯式地列舉出來,否則無法引用對象。但是不要將內(nèi)部標(biāo)識符和現(xiàn)實(shí)世界的屬性混淆了,內(nèi)部標(biāo)識符純粹是一種便于實(shí)現(xiàn)的做法,沒有應(yīng)用意義。相反,納稅人編號、汽車牌照號碼和電話號碼都不是內(nèi)部標(biāo)識符,因?yàn)樗鼈冊趯?shí)現(xiàn)世界有真實(shí)的意義,屬于合法的屬性。

(2)操作與方法

操作是一個(gè)函數(shù)或過程,比如,open和close都是Windows類的操作,類中所有的對象都共享相同的操作,因此將對象能夠做什么的行為稱為操作,通常將相同的操作應(yīng)用于許多不同的類稱為多態(tài)。

方法是對操作的實(shí)現(xiàn),其表現(xiàn)為OOP某個(gè)類的成員函數(shù)。比如,類Validator有一個(gè)操作validate,其校驗(yàn)過程是通過validate調(diào)用不同的函數(shù)實(shí)現(xiàn)的。比如,范圍值校驗(yàn)和奇偶校驗(yàn)。雖然這些方法在邏輯上都執(zhí)行相同的任務(wù)——數(shù)據(jù)校驗(yàn),但是每種方法的實(shí)現(xiàn)代碼會有所不同。

4.2所示RangeValidator類有min和max屬性,以及validate操作,min、max和validate都是RangeValidator的特征。特征是描述屬性或操作的類屬詞匯,類似地OddEvenValidator有isEven屬性和validate操作。

圖 4.2 操作的UML表示

注意,validate()省略了括號中的輸入?yún)?shù),即“validate(pThis:void *, value:int):bool”。validate的一個(gè)參數(shù)是pThis,其類型是void *;它的另一個(gè)參數(shù)value,其類型是int。當(dāng)一項(xiàng)操作在幾個(gè)類上都有方法時(shí),這些方法都要有相同的簽名,即相同的參數(shù)數(shù)量和類型,以及返回值的類型。

UML的方框表示類,最多有三格,從上到下每個(gè)格里分別包含了類名、屬性列表和操作列表。類方框中的屬性和操作的框格可以選擇顯示或隱藏,缺少屬性說明沒有指定屬性,缺少操作框說明沒有指定操作。相反,空框格意味著屬性是指定的,只是沒有顯示屬性而已。

操作列表約定用常規(guī)字體列出操作名,左對齊,首字母小寫。比如,參數(shù)列表和操作結(jié)果的類型,用括號將參數(shù)列表括起來,并用逗號分隔參數(shù)。結(jié)果類型之前有一個(gè)冒號,除非括號中空的參數(shù)列表明確表示沒有參數(shù),否則就不能下結(jié)論。

(3)客戶和服務(wù)器模式

在OOP中,如果一個(gè)類公開了一些方法供其它類調(diào)用,那么這個(gè)類被稱為服務(wù)器,公開的這些方法被稱為服務(wù),而調(diào)用這些服務(wù)的類就是客戶。理論上客戶類調(diào)用服務(wù)器類的服務(wù),即客戶向服務(wù)器發(fā)送了一條消息。而客戶和服務(wù)器的概念是相對而言的,當(dāng)A類向B類提供了功能接口時(shí),則類A是服務(wù)器,B類是客戶;如果類B也同時(shí)為類A提供了功能接口,則類B是服務(wù)器,類A是客戶。

設(shè)計(jì)良好的服務(wù)器應(yīng)該將其實(shí)現(xiàn)細(xì)節(jié)隱藏起來,客戶僅需知道服務(wù)器提供的接口即可。接口就是客戶所能調(diào)用的那些函數(shù),這些函數(shù)將消息發(fā)給服務(wù)器,那么服務(wù)器就知道客戶需要什么樣的服務(wù),服務(wù)器會返回一些數(shù)據(jù)給客戶,或執(zhí)行客戶所需的任務(wù)等。

(4)消息傳遞和方法調(diào)用

在OOP中,類和對象表現(xiàn)為服務(wù)器,使用類和對象的模塊表現(xiàn)為客戶??蛻敉ㄟ^特殊的方式請求服務(wù)。那么到底如何讓對象為我們做有用的事情呢?必須有一種方法能向?qū)ο笞龀稣埱螅沟盟茏瞿臣虑椋热?,完成交易、在屏幕上畫圖或打開開關(guān)??梢韵?qū)ο蟀l(fā)出的請求是由它的接口定義的,而接口是由類型定義的。

雖然接口規(guī)定了我們能向特定的對象發(fā)出什么請求,但必須有代碼滿足這種請求,再加上隱藏的數(shù)據(jù)就組成了實(shí)現(xiàn)。類型對每個(gè)可能的請求都有一個(gè)相關(guān)的函數(shù),當(dāng)向?qū)ο蟀l(fā)出請求時(shí),就調(diào)用這個(gè)函數(shù)。這個(gè)過程被概括為向?qū)ο蟆鞍l(fā)送消息”(提出請求),對象根據(jù)這個(gè)消息確定做什么(執(zhí)行代碼)。

對象之間的邏輯接口通過消息傳遞實(shí)現(xiàn),消息是對對象之間通信的的抽象。常見的消息傳遞方法是直接調(diào)用定義于接收方對象中的操作,比如,當(dāng)對象A調(diào)用對象B的一個(gè)方法時(shí),對象A就是在向?qū)ο驜發(fā)送一個(gè)消息,對象B的響應(yīng)由其返回值定義,但只有對象的公共方法才能由另一個(gè)對象調(diào)用。

使用消息傳遞可以實(shí)現(xiàn)松耦合,特別在分析階段,不用指定接口的細(xì)節(jié),比如,同步、函數(shù)調(diào)用格式和超時(shí)等。當(dāng)全面理解了所有的問題后,接下來就可以決定設(shè)計(jì)和實(shí)現(xiàn)的細(xì)節(jié)了。通常對象接口可以看成對象與外部世界之間制定的契約,契約是由一組協(xié)議定義的,對象參與到這些協(xié)議中。接口協(xié)議包括前置條件、后置條件和不變量。

前置條件是當(dāng)該操作被調(diào)用時(shí),必須成立的條件。即在調(diào)用之前應(yīng)該校驗(yàn)傳入?yún)?shù)是否正確,只有正確才能執(zhí)行該方法。也就是說,必須在消息發(fā)送或接收之前保證為真的條件,這是消息發(fā)送者的職責(zé)。一旦通過前置條件的校驗(yàn)方法必須執(zhí)行,且必須保證執(zhí)行結(jié)果符合契約,這就是后置條件。也就是說,后置條件是當(dāng)該操作完成時(shí),必須成立的條件。即在處理消息時(shí)必須保證為真,這是消息接收者的職責(zé)。不變量是指在任何時(shí)刻都必須成立的條件,包括操作執(zhí)行前、執(zhí)行時(shí)和執(zhí)行后。

(5)屬性抽象與行為抽象

OO程序設(shè)計(jì)思想可以采用抽象的方法,對現(xiàn)實(shí)世界中的多個(gè)具體對象進(jìn)行概括分析,得到這類對象所具有的共同屬性和行為,加以描述就形成了類。雖然都是同一個(gè)類的對象,但每個(gè)對象的屬性不同,于是就形成了不同的具體對象實(shí)體。

抽象一般分為屬性抽象和行為抽象兩種,屬性抽象是尋找一類對象共有的屬性,比如,在范圍值校驗(yàn)器RangeValidator類中,使用整型變量min和max來描述push到棧中的數(shù)值范圍,然后將min和max變量作為類的成員變量描述對象的屬性,即“屬性是包含在對象中的變量”。而行為抽象則是尋找這類對象所具有的共同行為特征,比如,對push到棧中的值進(jìn)行范圍值校驗(yàn),同樣,也可以為這個(gè)類添加相應(yīng)的函數(shù),最終將該函數(shù)作為類的成員函數(shù)描述對象的行為,即“方法是包含在對象中的函數(shù)”。

在面向過程的編程中,程序是由模塊組成的,一個(gè)模塊就是一個(gè)過程,通常采用自頂而下的設(shè)計(jì)方法。而面向?qū)ο蟮木幊膛c設(shè)計(jì)著眼于解決面向過程的編程和自頂而下設(shè)計(jì)中出現(xiàn)的一些問題,由于在面向?qū)ο蟮木幊讨袠?gòu)成模塊的基本單元是類,而不是過程,因此面向?qū)ο笤O(shè)計(jì)是面向?qū)ο缶幊痰脑O(shè)計(jì)方法,它著重于類的設(shè)計(jì),通過類的設(shè)計(jì)完成對實(shí)體的建模任務(wù),類建模的目的是描述對象。

在面向過程的編程中,描述一個(gè)物體時(shí),數(shù)據(jù)和方法是分開的。比如,當(dāng)通過網(wǎng)絡(luò)發(fā)送信息時(shí),則只會發(fā)送相關(guān)的數(shù)據(jù),并認(rèn)為網(wǎng)絡(luò)另一端的程序知道如何進(jìn)行處理。也就是說,如果兩者之間沒有握手協(xié)議,則網(wǎng)絡(luò)另一端的程序不知道如何處理。而對象可以定義為“同時(shí)包含”數(shù)據(jù)和行為的一個(gè)實(shí)例,即通過封裝機(jī)制將數(shù)據(jù)和行為捆綁在一起,形成一個(gè)完整的、具有屬性和行為的對象。比如,當(dāng)通過網(wǎng)絡(luò)傳送對象時(shí),則傳送的是整個(gè)對象。因此使用OO技術(shù)的程序?qū)嶋H上就是多個(gè)對象的集合,這里的“同時(shí)包含”正是OO程序設(shè)計(jì)與面向過程程序設(shè)計(jì)方法的重要區(qū)別。

由此可見,以后在分析新的對象時(shí),都要從屬性和行為兩個(gè)方面進(jìn)行抽象和概括,提取對象的共同特征,而整個(gè)抽象過程是一個(gè)從具體到一般的過程。如果說抽象是將很多對象的共有特征提取出來成為類的成員屬性和成員函數(shù),那么封裝機(jī)制則是將這些特征進(jìn)行有機(jī)地結(jié)合形成一個(gè)完整的類。

>>>1.1.3 封裝

類和對象既是獨(dú)立的概念,又密切相關(guān)。每個(gè)對象都是某個(gè)類的一個(gè)實(shí)例,每個(gè)類都有0或多個(gè)實(shí)例。對于所有的應(yīng)用來說,類幾乎都是靜態(tài)的。這就意味著,對象一旦被創(chuàng)建,它的類就確定了。

雖然最具挑戰(zhàn)的是如何確定類和對象但只要正確使用面向?qū)ο蠓治?/span>(Ogject Oriented Analysis,OOA)和面向?qū)ο笤O(shè)計(jì)(Object Oriented Design,OOD)就能得到具有價(jià)值的領(lǐng)域模型和設(shè)計(jì)模型。OOA、OOD與OOP到底是什么關(guān)系?OOA的結(jié)果可以作為OOD開始的模型,OOD的結(jié)果可以作為藍(lán)圖,利用OOP方法實(shí)現(xiàn)一個(gè)系統(tǒng)。

在OOA和OOD中,不需要考慮特定的語言機(jī)制,“關(guān)鍵是尋找并解決業(yè)務(wù)問題,完成概念分析和設(shè)計(jì)。在OOA和OOD的早期,開發(fā)者的主要任務(wù)有兩項(xiàng):

● 從需求的詞匯表中確定類;

● 創(chuàng)建一些結(jié)構(gòu),讓多組對象一起工作,提供滿足需求的行為。

通常我們將這樣的類和對象統(tǒng)稱為問題域的關(guān)鍵抽象,即關(guān)鍵抽象反映了問題域的詞匯表,可以從問題域中發(fā)現(xiàn),也可以作為設(shè)計(jì)的一部分發(fā)明;將這些協(xié)作結(jié)構(gòu)稱為實(shí)現(xiàn)的機(jī)制,其考慮的是許多不同類型的對象之間的協(xié)作活動。

確定關(guān)鍵抽象包括兩個(gè)過程:發(fā)現(xiàn)和發(fā)明,通過與領(lǐng)域?qū)<遥ㄓ脩簦┙涣?,將會發(fā)現(xiàn)領(lǐng)域?qū)<宜褂玫某橄蟆H绻I(lǐng)域?qū)<姨峒八?,那么這個(gè)抽象通常是很重要的,比如,范圍值校驗(yàn)器RangeValidator。而發(fā)明就是創(chuàng)造新的類和對象的過程,雖然它們不一定是問題域的組成部分,但在設(shè)計(jì)或?qū)崿F(xiàn)中也是很重要的。比如,微型數(shù)據(jù)庫、鏈表、棧、隊(duì)列等。這些關(guān)鍵抽象是具體設(shè)計(jì)的結(jié)果,不屬于問題域。因此在設(shè)計(jì)過程中,開發(fā)者不僅需要考慮單個(gè)類的設(shè)計(jì),還要考慮這些類的實(shí)例如何一起工作,并使用場景驅(qū)動分析過程。由此可見,關(guān)鍵抽象反映了業(yè)務(wù)領(lǐng)域的抽象,機(jī)制是設(shè)計(jì)的靈魂。

假設(shè)希望對push到棧中的值,既可以進(jìn)行范圍值校驗(yàn),也可以進(jìn)行偶校驗(yàn)。從面向?qū)ο蟮慕嵌葋砜?,首先要從問題的描述中發(fā)現(xiàn)對象,當(dāng)找到對象后,接著開始通過共性和差異性分析這些對象所具有的屬性和行為,然后利用面向?qū)ο蟮姆庋b機(jī)制將其封裝成類。

根據(jù)問題的描述,范圍值校驗(yàn)器就是一個(gè)RangeValidator具體類,其屬性是范圍值校驗(yàn)參數(shù)min和max,其行為就是將符合范圍要求的數(shù)值push到棧中。因此只要將RangeValidator的屬性和行為作為成員封裝到結(jié)構(gòu)體中,就形成了RangeValidator類,這是面向過程編程的C程序員最容易想到,也最容易理解的方法。

為了支持這種風(fēng)格,C允許將方法作為某個(gè)結(jié)構(gòu)體的一部分來聲明,那么操作存儲在結(jié)構(gòu)體中的數(shù)據(jù)就很容易了,詳見程序清單 2.18。

程序清單4.1范圍值校驗(yàn)器類接口

1 typedef struct _RangeValidator{

2 bool (*const RangeValidate)(struct _RangeValidator *pThis, int value);

3 const int min;

4 const int max;

5 }RangeValidator;

6

7 RangeValidator rangeValidator;

其中,類名字的首字母為大寫,對象名字的首字母為小寫。由此可見,通過擴(kuò)展已有結(jié)構(gòu)體的概念創(chuàng)造了一個(gè)全新的概念——類,類如同種類一樣定義一個(gè)類就是在創(chuàng)造一個(gè)新的數(shù)據(jù)類型。雖然聲明一個(gè)類的變量如同聲明一個(gè)結(jié)構(gòu)體的變量一樣,但聲明一個(gè)類的變量被稱為對象,因此有了類即可聲明一個(gè)RangeValidator類的對象rangeValidator通常也稱rangeValidator對象是RangeValidator類的一個(gè)實(shí)例,就是創(chuàng)建類的一個(gè)實(shí)例的過程。

在進(jìn)行范圍值校驗(yàn)時(shí),首先需要判斷value值是否符合要求?validateRange()函數(shù)接口的實(shí)現(xiàn)詳見程序清單 2.19。

程序清單 4.2 范圍值校驗(yàn)器接口函數(shù)的實(shí)現(xiàn)

1 bool validateRange(RangeValidator *pThis, int value)

2 {

3 return pThis -> min <= value && value <= pThis -> max;

4 }

偶校驗(yàn)器OddEvenValidator具體類和對象oddEvenValidator的定義詳見程序清單 2.20。

程序清單 4.3 偶校驗(yàn)器類接口

1 typedef struct _OddEvenValidator{

2 bool (*const OddEvenValidate)(struct _OddEvenValidator *pThis, int value);

3 bool isEven;

4 }OddEvenValidator;

5

6 OddEvenValidator oddEvenValidator;

在進(jìn)行偶校驗(yàn)時(shí),同樣需要判斷value值是否符合要求?validateOddEven()函數(shù)接口的實(shí)現(xiàn)詳見程序清單 2.21

程序清單 4.4 偶校驗(yàn)器接口函數(shù)的實(shí)現(xiàn)

1 bool validateOddEven(OddEvenValidator *pThis, int value)

2 {

3 return (!pThis -> isEven && (value % 2)) || (pThis -> isEven && !(value % 2));

4 }

顯然,無論是什么校驗(yàn)器,其共性是value值合法性判斷,因此可以共用一個(gè)函數(shù)指針,即特殊的函數(shù)指針類型RangeValidate和OddEvenValidate被泛化成了一般的函數(shù)指針類型Validate。其次,由于每個(gè)函數(shù)都有一個(gè)指向當(dāng)前對象的pThis指針,因此特殊的結(jié)構(gòu)體類型RangeValidator *和OddEvenValidator *被泛化成了void *類型,即可接受任何類型的數(shù)據(jù)

1 typedef bool(*const Validate)(void *pThis, int value);

2 typedef struct{

3 Validate validate;

4 const int min;

5 const int max;

6 }RangeValidator;

7

8 typedef struct{

9 Validate validate;

10 bool isEven;

11 }OddEvenValidator;

校驗(yàn)器泛化接口的實(shí)現(xiàn)詳見程序清單 2.22。

程序清單 4.5 通用校驗(yàn)器接口的實(shí)現(xiàn)(validator.c)

1 #include "validator.h"

2

3 bool validateRange(void *pThis, int value)

4 {

5 RangeValidator *pRangeValidator = (RangeValidator *)pThis;

6 return pRangeValidator -> min <= value && value <= pRangeValidator -> max;

7 }

8

9 bool validateOddEven(void *pThis, int value)

10 {

11 OddEvenValidator *pOddEvenValidator = (OddEvenValidator *)pThis;

12 return (!pOddEvenValidator -> isEven && (value % 2)) ||

13 (pOddEvenValidator -> isEven && !(value % 2));

14 }

為了便于閱讀,程序清單 4.6展示了范圍值校驗(yàn)器和奇偶校驗(yàn)器的接口。

程序清單 4.6 通用校驗(yàn)器接口(validator.h)

1 #pragma once;

2 #include

3

4 typedef bool(*const Validate)(void *pThis, int value);

5 typedef struct{

6 Validate validate;

7 const int min;

8 const int max;

9 }RangeValidator;

10

11 typedef struct{

12 Validate validate;

13 bool isEven;

14 }OddEvenValidator;

15

16 bool validateRange(void *pThis, int value);

17 bool validateRange(void *pThis, int value);

18 #define newRangeValidator(min, max) {(validateRange), (min), (max)} // 初始化RangeValidator

19 #define newOddEvenValidator(isEven) {{validateOddEven}, (isEven)} // 初始化OddEvenValidator

這個(gè)接口主要由所有的操作聲明構(gòu)成,這些操作適用于這個(gè)類的所有對象,詳見圖 4.3。

圖 4.3 類圖

以范圍值校驗(yàn)器為例,假設(shè)min=0,max=9,使用名為newRangeValidator的宏將結(jié)構(gòu)體初始化的使用方法如下:

RangeValidator rangeValidator = newRangeValidator(0, 9);

注意,RangeValidator類是在編譯時(shí)定義的,rangeValidator對象是在運(yùn)行時(shí)作為類的實(shí)例創(chuàng)建的。宏展開后如下

RangeValidator rangeValidator = {{validateRange}, (0), (9)};

其相當(dāng)于

rangeValidator.validate = validateRange;

rangeValidator.min = 0;

rangeValidator.max = 9;

如果有以下定義

void * pValidator = &rangeValidator;

即可通過pValidator引用RangeValidatorminmax。校驗(yàn)函數(shù)的調(diào)用方式如下

(RangeValidator *)pValidator -> validate(pValidator, 8);

以上調(diào)用形式的前提是已知pValidator指向了確定的結(jié)構(gòu)體類型,如果pValidator將指向未知的校驗(yàn)器,顯然以上調(diào)用形式無法做到通用那么如何調(diào)用?

雖然pValidator&rangeValidator.validate的類型不一樣,但它們的值相等,因此可以利用這一特性獲取validateRange()函數(shù)的地址。即:

Validate validate = *((Validate *)pValidator);

其調(diào)用形式如下:

validate(pValidator, 8);

根據(jù)OCP開閉原則,由于不允許修改push()函數(shù),因此需要編寫一個(gè)通用的擴(kuò)展push功能的pushWithValidate()函數(shù),詳見程序清單 4.7。

程序清單 4.7 pushWithValidate()

1 bool pushWithValidate(stackADT stack, void *pValidator, int value)

2 {

3 Validate validate = *((Validate*)pValidator);

4 if (pValidator && !validate(pValidator, value)){

5 return false;

6 }

7 return push(stack, value);

8 }

其中,stack是指向當(dāng)前對象(棧)的指針,用于請求對象對自身執(zhí)行某些操作,而結(jié)構(gòu)體的成員變量就是通過stack指針找到自己所屬的對象的。pValidator為指向校驗(yàn)器的指針,如果無需校驗(yàn),則將pValidator置NULL并返回true。

使用validator.h接口的通用校驗(yàn)器范例程序詳見程序清單 4.8。

程序清單 4.8 通用校驗(yàn)器使用范例程序

1 #include

2 #include"Stack.h"

3 #include"validator.h"

4 // 添加pushWithValidate()函數(shù)

5 int main(int argc, int *argv[])

6 {

7 stackADT stack;

8 int temp;

9

10 stack = newStack();

11 RangeValidator rangeValidator = newRangeValidator(0, 9);

12 for (int i = 0; i < 16; i ++){

13 pushWithValidate(stack, &rangeValidator, i);

14 }

15 while (!stackIsEmpty(stack)) {

16 pop(stack, &temp);

17 printf("%d ", temp);

18 }

19 printf("\n");

20 OddEvenValidator oddEvenValidator = newOddEvenValidator(true);

21 for (int i = 0; i<16; i++){

22 pushWithValidate(stack, &oddEvenValidator, i);

23 }

24 while (!stackIsEmpty(stack)) {

25 pop(stack, &temp);

26 printf("%d ", temp);

27 }

28 freeStack(stack);

29 return 0;

30 }

由此可見,雖然在結(jié)構(gòu)體內(nèi)置函數(shù)指針也可以創(chuàng)建類,但其中的每個(gè)類都是一個(gè)獨(dú)立的單元,每個(gè)都要從頭開始。且不同類之間沒有任何關(guān)系,因?yàn)槊總€(gè)類的開發(fā)者都根據(jù)自己的選擇提供方法。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 周立功
    +關(guān)注

    關(guān)注

    38

    文章

    130

    瀏覽量

    37438

原文標(biāo)題:周立功:類是具有共同的行為和特征的所有對象的集合

文章出處:【微信號:Zlgmcu7890,微信公眾號:周立功單片機(jī)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》周立功數(shù)十年心血力作

    為了將實(shí)際開發(fā)過程中總結(jié)的有價(jià)值的技術(shù)應(yīng)用分享給大家,周立功及其團(tuán)隊(duì)整理出《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》這本書,其內(nèi)容如同培訓(xùn)講師的教案,是周立功和團(tuán)隊(duì)的讀書筆記和程序設(shè)計(jì)實(shí)踐的心得。
    發(fā)表于 05-26 10:06 ?26次閱讀

    周立功“程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)”:深度解剖動態(tài)分布內(nèi)存的free()函數(shù)與realloc()函數(shù)

    周立功教授數(shù)年之心血之作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》,書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。
    的頭像 發(fā)表于 08-25 14:22 ?1.5w次閱讀

    新書創(chuàng)作談:周立功教授數(shù)十年之心血力作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)

    ` 近日,周立功教授公開了數(shù)十年之心血力作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》,此書在4月28日落筆,電子版已無償性分享到電子工程師與高校群體,在致遠(yuǎn)電子公眾號后臺回復(fù)關(guān)鍵字【程序設(shè)計(jì)】可在線閱讀。 在程序
    發(fā)表于 05-15 18:04

    【完整資料】《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》周立功數(shù)十年心血力作

    `近日,周立功教授公開了數(shù)十年之心血力作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》,此書在4月28日落筆,電子版已無償性分享到電子工程師與高校群體。在程序設(shè)計(jì)過程中,很多開發(fā)人員在沒有全局思維的把控,科學(xué)、系統(tǒng)的組織
    發(fā)表于 05-16 16:43

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)

    本帖最后由 lee_st 于 2017-10-31 09:04 編輯 程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)(僅供閱覽不可印刷)
    發(fā)表于 10-21 20:09

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)

    本帖最后由 lee_st 于 2018-6-16 02:32 編輯 程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)(僅供閱覽不可印刷)
    發(fā)表于 06-15 02:33

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》【完整資料】分享!

    現(xiàn)象,甚至成為一位閱讀程序者。 為了將實(shí)際開發(fā)過程中總結(jié)的有價(jià)值的技術(shù)應(yīng)用分享給大家,周立功及其團(tuán)隊(duì)整理出《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》這本書,其內(nèi)容如同培訓(xùn)講師的教案,是周立功和團(tuán)隊(duì)的讀書筆記和程序
    發(fā)表于 08-31 16:20

    數(shù)據(jù)結(jié)構(gòu)及應(yīng)用算法教學(xué)課件

    課程簡介 《數(shù)據(jù)結(jié)構(gòu)》作為一門獨(dú)立的課程最早是美國的一些大學(xué)開設(shè)的,1968年美國唐·歐·克努特教授開創(chuàng)了數(shù)據(jù)結(jié)構(gòu)的最初體系,他所著的《計(jì)算機(jī)程序設(shè)計(jì)技巧》第
    發(fā)表于 09-05 11:24 ?0次下載

    新書創(chuàng)作談:周立功教授數(shù)十年之心血力作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)

    近日,周立功教授公開了數(shù)十年之心血力作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》,此書在4月28日落筆,電子版已無償性分享到電子工程師與高校群體,在致遠(yuǎn)電子公眾號后臺回復(fù)關(guān)鍵字【程序設(shè)計(jì)】可在線閱讀。
    發(fā)表于 05-08 09:32 ?1963次閱讀

    算法與數(shù)據(jù)結(jié)構(gòu)——哈希表

    周立功教授數(shù)年之心血之作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》以及《面向第三章為算法與數(shù)據(jù)結(jié)構(gòu),本文為3.5 哈希表。
    的頭像 發(fā)表于 09-25 11:37 ?5412次閱讀
    算法與<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>——哈希表

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》——框架與重用

    周立功教授數(shù)年之心血之作《程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)》以及《面向AMetal框架與接口的編程(上)》,電子版已無償性分享到電子工程師與高校群體,在公眾號回復(fù)【編程】即可在線閱讀。書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。
    的頭像 發(fā)表于 10-10 10:55 ?5394次閱讀
    《<b class='flag-5'>程序設(shè)計(jì)</b>與<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>》——框架與重用

    嵌入式軟件工程電子書之周立功程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)

    本文詳細(xì)介紹了嵌入式軟件工程中的程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)相關(guān)知識。 在學(xué)習(xí)程序設(shè)計(jì)時(shí),很多初學(xué)者常常會陷入這樣的誤區(qū),他們總將阻礙個(gè)人成長的原因歸結(jié)為缺少機(jī)會。其實(shí)問題的根源在于缺乏方法論,很少有人將
    發(fā)表于 10-25 17:45 ?4次下載

    什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析

    本文檔的主要內(nèi)容詳細(xì)介紹的是什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析包括了:數(shù)據(jù)結(jié)構(gòu)在串口通信當(dāng)中的應(yīng)用,數(shù)據(jù)結(jié)構(gòu)在按鍵
    發(fā)表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?為什么要學(xué)習(xí)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>的應(yīng)用實(shí)例分析

    ACM程序設(shè)計(jì)常用算法與數(shù)據(jù)結(jié)構(gòu)參考

    ACM程序設(shè)計(jì)常用算法與數(shù)據(jù)結(jié)構(gòu)參考(核達(dá)中遠(yuǎn)通電源技術(shù)有限公司招聘電話)-如今的程序設(shè)計(jì)已不再是個(gè)人英雄時(shí)代了,程序的設(shè)計(jì)和開發(fā)實(shí)施需要靠團(tuán)隊(duì)成員的積極配合和合作。軟件技術(shù)在當(dāng)今時(shí)代
    發(fā)表于 09-22 18:02 ?2次下載
    ACM<b class='flag-5'>程序設(shè)計(jì)</b>常用算法與<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>參考

    程序設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)(嵌入式)

    編程的基礎(chǔ)-算法和數(shù)據(jù)結(jié)構(gòu)入門資料免費(fèi)下載。
    發(fā)表于 04-18 09:35 ?1次下載