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

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

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

面向?qū)ο缶幊獭惻c對(duì)象

AGk5_ZLG_zhiyua ? 來源:未知 ? 作者:佚名 ? 2017-09-27 15:36 ? 次閱讀

周立功教授數(shù)年之心血之作《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》以及《面向AMetal框架與接口編程(上)》,電子版已無償性分享到電子工程師與高校群體,書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。經(jīng)周立功教授授權(quán),本公眾號(hào)特對(duì)《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》一書內(nèi)容進(jìn)行連載,愿共勉之。

第四章為面向?qū)ο缶幊?/span>,本文為4.2 類與對(duì)象。

4.2 類與對(duì)象

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

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

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

>>>4.2.1對(duì)象

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

>>>4.2.2 類

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

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

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

在現(xiàn)實(shí)世界里,餅干也是對(duì)象,必須先有模子(類),才能做出你想要的形狀的餅干,因此可以認(rèn)為類是對(duì)象的模板。比如,只有符合一定條件的數(shù)值才能push到棧中,那么Validator校驗(yàn)器類就是由RangeValidator范圍值校驗(yàn)器類、OddEvenValidator奇偶校驗(yàn)器類和PrimerValidator質(zhì)數(shù)校驗(yàn)器類等具體校驗(yàn)器類的對(duì)象構(gòu)成的一個(gè)集合體。屬于類的任何對(duì)象都共享該類的所有屬性,比如,所有的具體校驗(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è)對(duì)象都擁有的一個(gè)值,可以這樣類比——對(duì)象之于類如同值之于屬性。比如,name、birthdate和weight都是Person對(duì)象的屬性,color、modelYear和weight都是Car對(duì)象的屬性。對(duì)于每個(gè)對(duì)象,每個(gè)屬性都有一個(gè)值,比如,對(duì)象ZhangSan的屬性birthdate的值是“21 October 1983”,也就是說,ZhangSan生于1983年10月21日。對(duì)于一個(gè)特定的屬性,不同的對(duì)象可能會(huì)有相同或不同的取值。在一個(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)建對(duì)象模型時(shí),盡可能不要在類圖中包含太多的信息,這樣就能集中注意力于整體設(shè)計(jì),而不會(huì)將重點(diǎn)放在細(xì)節(jié)上。

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

圖 4.1 屬性和值的UML表示法

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

(2)操作與方法

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

方法是對(duì)操作的實(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)代碼會(huì)有所不同。

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

圖 4.2 操作的UML表示法

注意,validate()省略了括號(hào)中的輸入?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ī)字體列出操作名,左對(duì)齊,首字母小寫。比如,參數(shù)列表和操作結(jié)果的類型,用括號(hào)將參數(shù)列表括起來,并用逗號(hào)分隔參數(shù)。結(jié)果類型之前有一個(gè)冒號(hào),除非括號(hào)中空的參數(shù)列表明確表示沒有參數(shù),否則就不能下結(jié)論。

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

在OOP中,如果一個(gè)類公開了一些方法供其它類調(diào)用,那么這個(gè)類被稱為服務(wù)器,公開的這些方法被稱為服務(wù),而調(diào)用這些服務(wù)的類就是客戶。理論上客戶類調(diào)用服務(wù)器類的服務(wù),即客戶向服務(wù)器發(fā)送了一條消息。而客戶和服務(wù)器的概念是相對(duì)而言的,當(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ù)器會(huì)返回一些數(shù)據(jù)給客戶,或執(zhí)行客戶所需的任務(wù)等。

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

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

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

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

使用消息傳遞可以實(shí)現(xiàn)松耦合,特別在分析階段,不用指定接口的細(xì)節(jié),比如,同步、函數(shù)調(diào)用格式和超時(shí)等。當(dāng)全面理解了所有的問題后,接下來就可以決定設(shè)計(jì)和實(shí)現(xiàn)的細(xì)節(jié)了。通常對(duì)象接口可以看成對(duì)象與外部世界之間制定的契約,契約是由一組協(xié)議定義的,對(duì)象參與到這些協(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ì)思想可以采用抽象的方法,對(duì)現(xiàn)實(shí)世界中的多個(gè)具體對(duì)象進(jìn)行概括分析,得到這類對(duì)象所具有的共同屬性和行為,加以描述就形成了類。雖然都是同一個(gè)類的對(duì)象,但每個(gè)對(duì)象的屬性不同,于是就形成了不同的具體對(duì)象實(shí)體。

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

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

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

>>>4.2.3 封裝

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

雖然最具挑戰(zhàn)的是如何確定類和對(duì)象,但只要正確使用面向?qū)ο蠓治觯∣gject 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),讓多組對(duì)象一起工作,提供滿足需求的行為。

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

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

假設(shè)希望對(duì)push到棧中的值,既可以進(jìn)行范圍值校驗(yàn),也可以進(jìn)行偶校驗(yàn)。從面向?qū)ο蟮慕嵌葋砜矗紫纫獜膯栴}的描述中發(fā)現(xiàn)對(duì)象,當(dāng)找到對(duì)象后,接著開始通過共性和差異性分析這些對(duì)象所具有的屬性和行為,然后利用面向?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)體的一部分來聲明,那么操作存儲(chǔ)在結(jié)構(gòu)體中的數(shù)據(jù)就很容易了,詳見程序清單 4.1。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

圖 4.3 類圖

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

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

其相當(dāng)于:

如果有以下定義:

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

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

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

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

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

程序清單 4.7 pushWithValidate()

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

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

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

由此可見,雖然在結(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)投訴
  • 對(duì)象
    +關(guān)注

    關(guān)注

    1

    文章

    38

    瀏覽量

    17340

原文標(biāo)題:周立功:類與對(duì)象的應(yīng)用

文章出處:【微信號(hào):ZLG_zhiyuan,微信公眾號(hào):ZLG致遠(yuǎn)電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Python的面向對(duì)象編程詳解

    一般編程可分為面向過程編程,和面向對(duì)象編程。Python的
    發(fā)表于 09-04 16:35 ?452次閱讀
    Python的<b class='flag-5'>面向</b><b class='flag-5'>對(duì)象</b><b class='flag-5'>編程</b>詳解

    labview面向對(duì)象編程

    點(diǎn)擊學(xué)習(xí)>>《龍哥手把手教你學(xué)LabVIEW視覺設(shè)計(jì)》視頻教程使用LabVIEW面向對(duì)象編程方法,對(duì)于大型測試應(yīng)用程序來講,面向對(duì)象相對(duì)于
    發(fā)表于 11-24 11:01

    LabVIEW面向對(duì)象編程入門介紹

    LabVIEW面向對(duì)象編程入門介紹庫描述介紹
    發(fā)表于 11-20 10:51

    LabVIEW面向對(duì)象的ActorFramework(1)

    ` 本帖最后由 bollworm 于 2020-2-10 14:54 編輯 本系列文章主要闡述以下幾個(gè)問題:(1)什么是面向對(duì)象編程?(2)為什么要學(xué)習(xí)面向
    發(fā)表于 02-10 14:09

    如何用C語言實(shí)現(xiàn)面向對(duì)象編程

    、組合、多態(tài)等面向對(duì)象的功能,但C語言有struct和函數(shù)指針。我們可以用struct中的數(shù)據(jù)和函數(shù)指針,以此來模擬對(duì)象的行為。所以在正式開始設(shè)計(jì)模式前,先看看如何用C語言實(shí)現(xiàn)
    發(fā)表于 07-12 07:24

    面向對(duì)象編程及其三大特性 精選資料分享

    Oriented)是一種以過程為中心的編程思想。這些都是以什么正在發(fā)生為 目標(biāo)進(jìn)行編程,不同于面向對(duì)象的是誰在受影響。與面向
    發(fā)表于 07-21 08:38

    談?wù)?b class='flag-5'>面向對(duì)象編程

    工業(yè)控制系統(tǒng)的PLC程序中也可以采用這種設(shè)計(jì)思想,雖然我們無法實(shí)現(xiàn)面向對(duì)象的很多優(yōu)秀特點(diǎn)如“繼承”,甚至于它根本就不具備面向對(duì)象編程語言的特
    發(fā)表于 09-08 07:47

    面向對(duì)象編程語言的特點(diǎn)

    工業(yè)控制系統(tǒng)的PLC程序中也可以采用這種設(shè)計(jì)思想,雖然我們無法實(shí)現(xiàn)面向對(duì)象的很多優(yōu)秀特點(diǎn)如“繼承”,甚至于它根本就不具備面向對(duì)象編程語言的特
    發(fā)表于 09-08 07:44

    面向對(duì)象編程的基本概念及其特點(diǎn)

    ,但面向對(duì)象編程的基本概念就是的實(shí)例(即對(duì)象),我們只需要使用這種概念就可以了。在計(jì)算機(jī)編
    發(fā)表于 09-09 06:33

    面向對(duì)象編程介紹

    目錄一、面向對(duì)象編程介紹1.面向過程編程2.函數(shù)式編程3.
    發(fā)表于 12-13 07:22

    面向對(duì)象編程練習(xí)

    實(shí)驗(yàn) 3 面向對(duì)象編程練習(xí) 一、實(shí)驗(yàn)?zāi)康?    通過編程和上機(jī)實(shí)驗(yàn)理解 Java 語言是如何體現(xiàn)面向
    發(fā)表于 09-23 18:57 ?3009次閱讀

    plc面向對(duì)象編程架構(gòu)與實(shí)現(xiàn)

    面向對(duì)象編程是計(jì)算機(jī)高級(jí)語言的一種先進(jìn)的編程模式,在工業(yè)控制系統(tǒng)的PLC程序中也可以采用這種設(shè)計(jì)思想,雖然我們無法實(shí)現(xiàn)面向
    發(fā)表于 01-31 15:00 ?4143次閱讀
    plc<b class='flag-5'>面向</b><b class='flag-5'>對(duì)象</b><b class='flag-5'>編程</b>架構(gòu)與實(shí)現(xiàn)

    Labview面向對(duì)象編程快速入門教程

    面向對(duì)象編程中, 用來表示通用特性。 例如,假設(shè)有一個(gè)描述汽車的中定義了各種汽車的通
    發(fā)表于 07-31 08:00 ?81次下載
    Labview<b class='flag-5'>面向</b><b class='flag-5'>對(duì)象</b><b class='flag-5'>編程</b>快速入門教程

    西門子PLC面向對(duì)象編程

    ,但面向對(duì)象編程的基本概念是 的實(shí)例(即對(duì)象),我們只需要使用這個(gè)概念。在計(jì)算機(jī)
    發(fā)表于 04-17 11:41 ?4次下載
    西門子PLC<b class='flag-5'>面向</b><b class='flag-5'>對(duì)象</b><b class='flag-5'>編程</b>

    Python中的對(duì)象詳解

    Python 是一種面向對(duì)象編程語言,它支持對(duì)象。是一種用戶自定義的數(shù)據(jù)類型,用于定義
    的頭像 發(fā)表于 04-20 16:53 ?964次閱讀