抽象過(guò)程
所有編程語(yǔ)言都提供抽象機(jī)制,人們所能解決的問(wèn)題的復(fù)雜性直接取決于抽象的類型和質(zhì)量。
OOP 允許根據(jù)問(wèn)題來(lái)描述問(wèn)題,而不是根據(jù)運(yùn)行解決方案的計(jì)算機(jī)來(lái)描述問(wèn)題。
純粹的面向?qū)ο蟪绦蛟O(shè)計(jì)方法:
- 萬(wàn)物皆對(duì)象
- 程序是對(duì)象的集合
- 每個(gè)對(duì)象都有自己的由其他對(duì)象所構(gòu)成的存儲(chǔ)
- 每個(gè)對(duì)象都擁有類型
- 某一個(gè)特定類型的所有對(duì)象都可以接收同樣的信息
對(duì)象具有狀態(tài)、行為和標(biāo)識(shí)
每個(gè)對(duì)象都有一個(gè)接口
所有的對(duì)象都是唯一的,但同時(shí)也是具有相同特性和行為的對(duì)象所歸屬的類的一部分。
類描述了具有相同特性(數(shù)據(jù)元素)和行為(功能)的對(duì)象集合,所以一個(gè)類實(shí)際上就是一個(gè)數(shù)據(jù)類型。
面向?qū)ο蟪绦蛟O(shè)計(jì)的挑戰(zhàn)之一,就是在問(wèn)題空間的元素和解空間的對(duì)象之間創(chuàng)建一對(duì)一的映射。
每個(gè)對(duì)象都只能滿足某些請(qǐng)求,這些請(qǐng)求由對(duì)象的接口(interface)所定義,決定接口的便是類型。
接口確定了某一個(gè)特定對(duì)象所能發(fā)出的請(qǐng)求,但是,在程序中必須有滿足這些請(qǐng)求的代碼,這些代碼與隱藏的數(shù)據(jù)一起構(gòu)成了實(shí)現(xiàn)(implement)
每個(gè)對(duì)象都提供服務(wù)
當(dāng)正在試圖開(kāi)發(fā)或理解一個(gè)程序設(shè)計(jì),最好的方法之一就是將對(duì)象想象成“服務(wù)提供者”
高內(nèi)聚是軟件設(shè)計(jì)的基本質(zhì)量要求之一:這意味著一個(gè)軟件構(gòu)件的各個(gè)方面“組合的好”
被隱藏的具體實(shí)現(xiàn)
將程序開(kāi)發(fā)人員按照角色分為類創(chuàng)建者和客戶端程序員:
- 客戶端程序員的目標(biāo)是收集各種用來(lái)實(shí)現(xiàn)快速應(yīng)用開(kāi)發(fā)的類。
- 類創(chuàng)建者的目標(biāo)是構(gòu)建類,這種類只向客戶端程序員暴露必需的部分,而隱藏其他部分。
將實(shí)現(xiàn)隱藏起來(lái)可以減少程序的 bug,即訪問(wèn)控制,訪問(wèn)控制存在的原因:
- 讓客戶端程序員無(wú)法觸及他們不應(yīng)該觸及的部分。
- 允許庫(kù)設(shè)計(jì)者可以改變類內(nèi)部的工作方式而不擔(dān)心會(huì)影響到客戶端程序員。
Java 中的四種訪問(wèn)權(quán)限:
-
public:任何人都是可用的 -
private:除了類型創(chuàng)建者和類型的內(nèi)部方法之外任何人都不能訪問(wèn) -
protected:與private類似,差別在與繼承于該類的派生類可以訪問(wèn)protected成員 -
default:包訪問(wèn)權(quán)限,同一個(gè)包中其他類可以訪問(wèn)。
復(fù)用具體實(shí)現(xiàn)
代碼復(fù)用是面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言所提供的最了不起的優(yōu)點(diǎn)之一
組合(“has-a”關(guān)系):新的類可以由任意數(shù)量、類型的其他對(duì)象以任意可以實(shí)現(xiàn)新的類中想要的功能的方式組成。如果組合是動(dòng)態(tài)發(fā)生的,那么它通常被稱為“聚合”
*在建立新類時(shí),應(yīng)該首先考慮組合,而不是繼承,因?yàn)樗雍?jiǎn)單靈活。
繼承
兩個(gè)類型可以有相同的特性和行為,但是其中一個(gè)類型可能比另一個(gè)含有更多的特性。繼承使用基類型和派生類型的概念表示了這種類型之間的相似性。
一個(gè)基類型包含所有派生類所共享的特性和行為,可以創(chuàng)建一個(gè)基類型來(lái)表示系統(tǒng)中某些對(duì)象的核心概念,從基類型中派生出其他類型,來(lái)表示該核心可以被不同的方式實(shí)現(xiàn)。
通過(guò)繼承而產(chǎn)生的類型等價(jià)性是理解面向?qū)ο蟪绦蛟O(shè)計(jì)方法內(nèi)涵的重要門檻。
基類與派生類的相似性:所有可以發(fā)送給基類對(duì)象的消息同時(shí)也可以發(fā)送給派生類對(duì)象。
產(chǎn)生基類與派生類的差異性的兩種形式:
- 在派生類添加新方法
- 在派生類中改變現(xiàn)有基類的方法,即覆蓋
“是一個(gè)”與“像是一個(gè)”
- “是一個(gè)”(is-a):只是覆蓋,沒(méi)有添加新的方法。
- “像是一個(gè)”(is-like-a):添加了新的方法。
伴隨多態(tài)的可互換對(duì)象
在處理類型的層次結(jié)構(gòu)時(shí),把一個(gè)對(duì)象不當(dāng)做它所屬的特性類型來(lái)對(duì)待,而是將其當(dāng)做其基類的對(duì)象來(lái)對(duì)待,這一可以編寫(xiě)出不依賴于特定類型的代碼。
為了實(shí)現(xiàn)泛型,面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言使用了后期綁定的概念,當(dāng)向?qū)ο蟀l(fā)送消息時(shí),被調(diào)用的代碼直到運(yùn)行時(shí)才能確定。編譯器確保被調(diào)用方法的存在,并對(duì)調(diào)用參數(shù)和返回值執(zhí)行類型檢查,但是并不知道將被執(zhí)行的確切代碼。
Java 使用了一小段特殊的代碼來(lái)代替絕對(duì)地址調(diào)用。
在某些語(yǔ)言中(如C++),必須明確聲明希望某個(gè)方法具備后期綁定,而 Java 中,動(dòng)態(tài)綁定是默認(rèn)行為,不需要額外添加關(guān)鍵字來(lái)實(shí)現(xiàn)多態(tài)。
單根繼承結(jié)構(gòu)
所有的類都最終繼承自單一的基類,Java 中 這個(gè)類為
Object。
在單根繼承結(jié)構(gòu)中的所有對(duì)象都具有一個(gè)公用接口,所以它們歸根到底都是相同的基本類型。
單根繼承結(jié)構(gòu)使得垃圾回收的實(shí)現(xiàn)變得容易得多。
容器
- 不同容器提供了不同類型的接口和外部行為
- 不同容器對(duì)于某些操作具有不同的效率
參數(shù)化類型
容器是通過(guò)向下轉(zhuǎn)型實(shí)現(xiàn)的,容器知道元素轉(zhuǎn)型前的類型,則可以實(shí)現(xiàn)容器,這種解決方法即參數(shù)化類型,即泛型。
對(duì)象的創(chuàng)建和生命期
- Java 完全采用動(dòng)態(tài)內(nèi)存分配方式,每當(dāng)想要?jiǎng)?chuàng)建新對(duì)象時(shí),就要使用
new關(guān)鍵字來(lái)構(gòu)建此對(duì)象的動(dòng)態(tài)實(shí)例。 - Java 提供了“垃圾回收”機(jī)制,它可以自動(dòng)發(fā)現(xiàn)對(duì)象何時(shí)不再被使用,進(jìn)而銷毀它。
異常處理
大多數(shù)錯(cuò)誤機(jī)制的主要問(wèn)題在于,它們都依賴于程序員自身的警惕性,這種警惕性來(lái)源于一種共同的約定,而不是編程語(yǔ)言所強(qiáng)制的。這種機(jī)制容易被忽視。
被拋出的異常不像方法返回的錯(cuò)誤值和方法設(shè)置的用來(lái)表示錯(cuò)誤條件的標(biāo)志位那樣可以被忽略。異常不能被忽視,所以它保證一定會(huì)在某處得到處理。
異常處理不是面向?qū)ο蟮奶匦浴?/p>
本文首發(fā)于Code & Fun