我們之所以將自然界分解,組織成各種概念礁遣,并按其含義分類,主要是因?yàn)槲覀兪钦麄€(gè)口語(yǔ)交流社會(huì)共同遵守的協(xié)定的參與者,這個(gè)協(xié)定以語(yǔ)言的形式固定下來(lái)……除非贊成這個(gè)協(xié)定中規(guī)定的有關(guān)語(yǔ)言信息的組織和分類葱色,否則我們根本無(wú)法交談。
—— Benjamin Lee Whorf (1987~1941)
計(jì)算機(jī)革命起源于機(jī)器娘香,因此苍狰,編程語(yǔ)言的產(chǎn)生也始于對(duì)機(jī)器的模仿。
1. 抽象過程
所有編程語(yǔ)言都提供抽象機(jī)制烘绽×苷眩可以認(rèn)為,人們所能夠解決的問題的復(fù)雜性直接取決于抽象的類型和質(zhì)量安接。所謂的 “類型” 是指 “所抽象的是什么翔忽?”。
程序員必須建立起在機(jī)器模型(位于 “解空間” 內(nèi)赫段,這是你對(duì)問題建模的地方呀打,例如計(jì)算機(jī))和實(shí)際待解問題的模型(位于 “問題空間” 內(nèi),這是問題存在的地方糯笙,例如一項(xiàng)業(yè)務(wù))之間的聯(lián)系贬丛。建立這種映射是費(fèi)力的,而且這不屬于編程語(yǔ)言所固有的功能给涕,這使得程序難以編寫豺憔,并且維護(hù)代價(jià)高昂,同時(shí)也產(chǎn)生了作為副產(chǎn)物的 “編程方法” 行業(yè)够庙。
面向?qū)ο蠓绞酵ㄟ^向程序員提供表示問題空間中的元素的工具而更進(jìn)了一步恭应。這種表示方式非常通用,使得程序員不會(huì)受限于任何特定類型的問題耘眨。我們將問題空間中的元素及其在解空間中的表示稱為 “對(duì)象”昼榛。(你還需要一些無(wú)法類比為空間問題元素的對(duì)象。)這種思想的實(shí)質(zhì)是:程序可以通過添加新類型的對(duì)象使自身適用于某個(gè)特定問題剔难。因此胆屿,當(dāng)你在閱讀描述解決方案的代碼時(shí)奥喻,也是在閱讀問題的表述。相比以前我們所使用的語(yǔ)言非迹,這是一種更靈活和更強(qiáng)有力的語(yǔ)言抽象环鲤。所以, OOP 允許根據(jù)問題來(lái)描述問題憎兽,而不是根據(jù)運(yùn)行解決方案的計(jì)算機(jī)來(lái)描述問題冷离。但是它任然與計(jì)算機(jī)有聯(lián)系: 每個(gè)對(duì)象看起來(lái)都有點(diǎn)像一臺(tái)微型計(jì)算機(jī)——它具有狀態(tài),還具有操作纯命,用戶可以要求對(duì)象執(zhí)行這些操作西剥。如果要對(duì)現(xiàn)實(shí)世界中的對(duì)象做類比,那么說它具有特性和行為似乎不錯(cuò)亿汞。
Alan Kay 曾經(jīng)總結(jié)了第一個(gè)成功的面向?qū)ο笳Z(yǔ)言的五個(gè)基本特性蔫耽,這些特性表現(xiàn)了一種純粹的面向?qū)ο蟪绦蛟O(shè)計(jì)方式:
- 萬(wàn)物皆為對(duì)象
將對(duì)象視為奇特的變量,它可以存儲(chǔ)數(shù)據(jù)留夜,除此之外匙铡,你還可以要求它在自身上執(zhí)行操作。理論上講碍粥,你可以抽取待解決問題的任何概念化構(gòu)建(狗鳖眼,建筑物、服務(wù)等)嚼摩,將其表示為程序中的對(duì)象
- 程序是對(duì)象的集合钦讳,它們通過發(fā)送消息來(lái)告知彼此所需要做的。
想要請(qǐng)求一個(gè)對(duì)象枕面,就必須對(duì)該對(duì)象發(fā)送一條消息愿卒。更具體地說,可以把消息想象為對(duì)某個(gè)特定對(duì)象的方法的調(diào)用請(qǐng)求潮秘。
- 每個(gè)對(duì)象都有自己的由其他對(duì)象所構(gòu)成的存儲(chǔ)琼开。
換句話說,可以通過創(chuàng)建包含現(xiàn)有對(duì)象的包的方式來(lái)創(chuàng)建新類型的對(duì)象枕荞。因此柜候,可以在程序中構(gòu)建復(fù)雜的體系,同時(shí)將其復(fù)雜性隱藏在對(duì)象的簡(jiǎn)單性背后躏精。
- 每個(gè)對(duì)象都有其類型渣刷。
按照通用的說法,“每個(gè)對(duì)象都是其某各類(class)的一個(gè)實(shí)例(instance)”矗烛,這里 “類” 就是 “類型” 的同義詞辅柴。每個(gè)類最重要的區(qū)別于其他類的特性就是“可以發(fā)送什么樣的消息給它”。
- 某一特定類型的所有對(duì)象都可以接受同樣的消息。
這是一句以為深長(zhǎng)的表述碌嘀,你在稍后便會(huì)看到碾篡。因?yàn)?“圓形” 類型的對(duì)象同時(shí)也是 “幾何形” 類型的對(duì)象,所以一個(gè) “圓形” 對(duì)象必定能夠接受發(fā)送給 “幾何形” 對(duì)象的消息筏餐。這意味著可以編寫與 “幾何形” 交互并自動(dòng)處理所有與幾何性質(zhì)相關(guān)的事務(wù)的代碼。這種可替代性(substitutability)是 OOP 中最強(qiáng)有力的概念之一牡拇。
Booch 對(duì)對(duì)象提出了一個(gè)更加簡(jiǎn)潔的描述:對(duì)象具有狀態(tài)魁瞪、行為和標(biāo)識(shí)。這意味著每一個(gè)對(duì)象都可以擁有內(nèi)部數(shù)據(jù)(它們給出了該對(duì)象的狀態(tài))和方法(它們的行為)惠呼,并且每一個(gè)對(duì)象都可以唯一地與其他對(duì)象區(qū)分開來(lái)导俘,具體來(lái)說,就是每一個(gè)對(duì)象在內(nèi)存中都有一個(gè)唯一的地址剔蹋。
2. 每個(gè)對(duì)象都有一個(gè)接口
在面向?qū)ο蟪绦蛟O(shè)計(jì)中實(shí)際上進(jìn)行的是創(chuàng)建新的數(shù)據(jù)類型旅薄,但事實(shí)上所有的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言都使用了 class 這個(gè)關(guān)鍵字來(lái)表示數(shù)據(jù)類型。
類描述了具有相同特性(數(shù)據(jù)元素)和行為(功能)的對(duì)象集合泣崩,一個(gè)類實(shí)際上就是一個(gè)數(shù)據(jù)類型少梁。程序員通過定義類來(lái)適應(yīng)問題,而不再被迫只能使用現(xiàn)有的用來(lái)表示機(jī)器中的存儲(chǔ)單元的數(shù)據(jù)類型矫付】Γ可以根據(jù)需求,通過添加新的數(shù)據(jù)類型來(lái)擴(kuò)展編程語(yǔ)言买优。編程系統(tǒng)欣然接受新的類妨马,并且像對(duì)待內(nèi)置類型一樣地照管它們和進(jìn)行類型檢查。
面向?qū)ο蠓椒ú⒉皇莾H局限于構(gòu)建仿真程序杀赢。無(wú)論你是否贊成一下觀點(diǎn)烘跺,即任何程序都是你所設(shè)計(jì)的系統(tǒng)的一種仿真,面向?qū)ο蠹夹g(shù)的應(yīng)用確實(shí)可以將大量的問題容易地降解為一個(gè)簡(jiǎn)單地解決方案脂崔。
接口確定了對(duì)某一特定對(duì)象所能發(fā)出的請(qǐng)求滤淳。但是,在程序中必須有滿足這些請(qǐng)求的代碼砌左。這些代碼與隱藏?cái)?shù)據(jù)一起構(gòu)成了實(shí)現(xiàn)娇钱。從過程編程的觀點(diǎn)來(lái)看,這并不太復(fù)雜绊困。在類型中文搂,每一個(gè)可能的請(qǐng)求都有一個(gè)方法與之相關(guān)聯(lián),當(dāng)向?qū)ο蟀l(fā)送請(qǐng)求時(shí)秤朗,與之相關(guān)聯(lián)的方法就會(huì)被調(diào)用煤蹭。
3. 每個(gè)對(duì)象都提供服務(wù)
當(dāng)正在試圖開發(fā)或理解一個(gè)程序設(shè)計(jì)時(shí),最好的方法之一就是將對(duì)象想象為 “服務(wù)提供者”。程序本身將向用戶提供服務(wù)硝皂,它將通過調(diào)用其他對(duì)象提供服務(wù)來(lái)實(shí)現(xiàn)這一目的常挚。你的目標(biāo)就是去創(chuàng)建(或者最好是在現(xiàn)有代碼庫(kù)中尋找)能夠提供理想的服務(wù)來(lái)解決問題的一系列對(duì)象。
將對(duì)象看作服務(wù)提供者還有另外一個(gè)附帶的好處:它有助于提高對(duì)象的內(nèi)聚性稽物。高內(nèi)聚是軟件設(shè)計(jì)的基本質(zhì)量要求之一:這意味著一個(gè)軟件構(gòu)件(例如一個(gè)對(duì)象奄毡,當(dāng)然他也有可能是指一個(gè)方法或一個(gè)庫(kù))的各個(gè)方面 “組合” 得很好。人們?cè)谠O(shè)計(jì)對(duì)象時(shí)所面臨的一個(gè)問題是贝或,將過多的功能都塞在一個(gè)對(duì)象中吼过。
在良好的面向?qū)ο笤O(shè)計(jì)中,每個(gè)對(duì)象都可以很好地完成一項(xiàng)任務(wù)咪奖,但是它并不試圖做更多的事盗忱。
將對(duì)象作為服務(wù)提供者看待是一件偉大的簡(jiǎn)化工具,這不僅在設(shè)計(jì)過程中非常有用羊赵,而且當(dāng)其他人試圖理解你的代碼或重用某個(gè)對(duì)象時(shí)趟佃,如果他們看出了這個(gè)對(duì)象所能提供的服務(wù)的價(jià)值,它會(huì)使調(diào)整對(duì)象以適應(yīng)其設(shè)計(jì)的過程變得簡(jiǎn)單得多昧捷。
4. 被隱藏的具體實(shí)現(xiàn)
將程序開發(fā)人員按照角色分為類創(chuàng)建者(那些創(chuàng)建新數(shù)據(jù)類型的程序員)和客戶端程序員(那些在其應(yīng)用中使用數(shù)據(jù)類型的消費(fèi)者)是大有裨益的闲昭。客戶端程序員的目標(biāo)是收集各種用來(lái)實(shí)現(xiàn)快速應(yīng)用開發(fā)的類靡挥。類創(chuàng)建者的目標(biāo)是構(gòu)建類汤纸,這種類只向客戶端程序員暴露必須的部分,而隱藏其他部分芹血。
訪問控制的原因:
- 讓客戶端程序員無(wú)法觸及他們不應(yīng)該觸及的部分——這些部分對(duì)數(shù)據(jù)類型的內(nèi)部操作來(lái)說是必需的贮泞,但并不是客戶解決特定問題所需的接口的一部分。這對(duì)客戶端程序員來(lái)說其實(shí)是一項(xiàng)服務(wù)幔烛,因?yàn)樗麄兛梢院苋菀椎乜闯瞿切〇|西對(duì)他們來(lái)說很重要啃擦,而哪些東西可以忽略。
- 允許庫(kù)設(shè)計(jì)者可以改變類內(nèi)部的工作方式而不用擔(dān)心會(huì)影響到客戶端程序員饿悬。如果接口和實(shí)現(xiàn)可以清晰地分離并得以保護(hù)令蛉,那么你就可以輕而易舉地完成這項(xiàng)工作。
1.5 復(fù)用的具體實(shí)現(xiàn)
一旦類被創(chuàng)建并被測(cè)試完狡恬,那么它就應(yīng)該(在理想情況下)代表一個(gè)有用的代碼單元珠叔。事實(shí)證明,這種復(fù)用性并不容易達(dá)到我們所希望的哪種程度弟劲,產(chǎn)生一個(gè)可復(fù)用的對(duì)象設(shè)計(jì)需要豐富的經(jīng)驗(yàn)和敏銳的洞察力祷安。但是一旦你有了這樣的設(shè)計(jì),它就可供復(fù)用兔乞。代碼復(fù)用是面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言所提供的最了不起的優(yōu)點(diǎn)之一汇鞭。
最簡(jiǎn)單地復(fù)用某個(gè)類的方式就是直接使用該類的一個(gè)對(duì)象凉唐,此外也可以將那個(gè)類的一個(gè)對(duì)象置于某個(gè)新的類中。
使用現(xiàn)有的類合成新的類霍骄,所以這種概念被稱為組合(composition)台囱,如果組合是動(dòng)態(tài)發(fā)生的,那么它通常被稱為聚合(aggregation)读整。組合經(jīng)常被視為 “has-a” (擁有)關(guān)系簿训。
組合帶來(lái)了極大的靈活性。新類的成員對(duì)象通常都被聲明為 private米间,使得使用新類的客戶端程序員不能訪問它們强品。這也使得你可以在不干擾現(xiàn)有客戶端代碼的情況下,修改這些成員车伞。也可以在運(yùn)行時(shí)修改這些成員對(duì)象,以實(shí)現(xiàn)動(dòng)態(tài)修改程序的行為喻喳。繼承不具有這樣的靈活性另玖。