Thinking In Java Part01(抽象)

1、抽象過程
	所有編程語言都提供抽象機制,人們所能解決的問題的複雜性取決與抽象的類型和之類。彙編語言是對底層機器的輕微抽象。命令式語言(Fortran、Basic、C等)都是對彙編語言的抽象。他們所作的主要抽象仍邀請在解決問題時要基於計算機的結構,而不是基於所要解決問題的結構來考慮。
	面向對象方式通過向程序員提供表示問題空間中的元素的工具更進一步,使得我們不會受限於任何特定類型的問題。我們將問題空間中的元素機器在解空間中的表示稱爲“對象”。這種思想的實質是:程序可以通過添加新類型的對象使自身適用於某個特定問題。因此,當你在閱讀描述解決方案的代碼的同時,也是在閱讀問題的表述。OOP允許根據問題來描述問題,而不是根據允許解決方案的計算機來描述問題。但是每個對象看起來都有點像一臺微型計算機——它具有狀態,還具有操作,用戶可以要求對象執行這些操作。
	Alan Kay曾總結了第一個成功的面嚮對象語言、同時也是Java所基於的語言之一的SmallTalk的五個基本特性,這些特性表現了一種純粹的面向對象程序設計方式:
		1.1、萬物皆對象:將對象視爲奇特的變量,它可以存儲數據,除此之外,你還可以要求它在自身上執行操作。理論上講,你可以抽取待求解問題的任何概念化構建(狗、建築物、服務等),將其表示爲程序中的對象。
		1.2、程序是對象的集合,它們通過發送消息來告知彼此所要做的:要想請求一個都系,就必須對該對象發送一條消息。更具體地說,可以把消息想像爲對某個特定對象的方法的調用請求。
		1.3、每個對象都有自己的由其他對象所構成的存儲。換句話說,可以通過創建包含現有對象的包的方式來創建新類型的對象。因此,可以在程序中構建複雜的體系,同時將其複雜性隱藏在對象的簡單性背後。
		1.4、每個對象都擁有其類型:“每個對象都是某個類(class)的一個實例(instance)”,這裏“類”就是“類型”的同義詞。每個類最重要的區別於其他類的特性就是“可以發送什麼樣的消息給它”。
		1.5、某一特定類型的所有對象都可以接受同樣的信息:因爲“圓形”類型的對象同時也是“幾何形”類型的對象,所以一個“圓形”對象必定能夠接受發送給“幾何形”對象的信息。這意味着可以編寫與“幾何形”交互並自動處理所有與幾何形性質相關的事物的代碼。這種可替代性是OOP中最強有力的概念之一。
		Booch對對象提出了一個更加簡介的描述:對象具有狀態、行爲和標識。這以爲每一個對象都可以擁有內部數據(它們給出了該對象的狀態)和方法(它們產生行爲),並且每一個對象都可以唯一地與其他對象區分開來,具體來說 ,就是每一個對象在內存中都有一個唯一的地址(有一點過於受限,因爲對象可以存在於不同的機器和地址空間中,它們還可以被存儲在硬盤上,在這些情況下,對象的標識就必須由地址之外的某些東西來確定了)。

2、每個對象都有一個接口
	亞里士多德大概是第一個深入研究類型(type)的哲學家。所有的對象都是唯一的,但同時也是具有相同的特性和行爲的對象所歸屬的類的一部分。這種思想被直接應用於第一個面嚮對象語言Simula-67,它在程序中使用基本關鍵字class來引入新的類型。
	創建抽象數據類型(類)是面向對象程序設計的基本概念之一。抽象數據類型的運行方式與內置(built-in)類型幾乎完全一致:你可以創建某一類型的變量(按照面向對象說法,稱其爲對象或實例),然後操作這些變量(稱其爲發送消息或請求,發送消息,對象就知道要做什麼)。每個類的成員或元素都具有某種共性:每個賬戶都有結餘金額,每個出納都可以處理存款請求等。同時,每個成員都有其自身的狀態:每個賬戶都有不同的結餘金額,每個出納都有自己的姓名。因此,出納、客戶、賬戶、交易等都可以在程序中被表示成唯一的實體。這些實體就是都系,每一個對象都屬於定義了特性和行爲的某個特定的類。
	所有的面向對象程序設計語言都使用class這個關鍵字來表示數據類型。因爲類描述了具有相同特性(數據元素)和行爲(功能)的對象集合,所以一個類實際上就是一個數據類型。
	任何程序都是你所設計的系統的一種仿真。一旦類被建立,就可以隨心所欲的創建類的任意個對象,然後操作它們,就像它們是存在於你的待求解問題中的元素一樣。
	如何獲得有用的對象?必須有某種方式產生對對象的請求,使對象完成各種任務,如完成開關、更亮等。每個對象都只能滿足某些請求,這些請求由對象的接口(interface)所定義。	
	接口確定了對某一特定對象所能發出的請求。但是,在程序中必須有滿足這些請求的代碼,這些代碼與隱藏的數據一起構成了實現。在類型中,每一個可能的請求都有一個方法與之相關聯,當向對象發送請求時,與之相關聯的方法就會被調用。此過程通常被 概括爲:向某個對象“發送信息”(產生請求),這個對象便知道此消息的目的,然後執行對應的程序代碼。
	UML圖中每個類都用一個方框表示,類名在方框的頂部,你所關心的任何數據成員都描述在方框的中間部分,方法(隸屬於此對象的、用來接受你發給此對象的消息的函數)在方框的底部。通常,只有類名和公共方法被示於UML設計中。
3、每個對象都提供服務
	當正在試圖開發或理解一個程序設計時,最後的方法之一就是將對象想像爲“服務提供者”,程序本身將向用戶提供服務,它將通過調用其他對象提供的服務來實現這一目的。你的目標就是去創建能夠提供理想的服務來解決問題的一系列對象。
	在創建對象前,問自己“如果我可以將問題從表象中抽取出來,那麼什麼樣的對象可以解決我的問題?”如果正在創建一個簿記系統,那麼可以知道系統應該具有某些包括了預定義的簿記輸入屏幕的對象,一個執行簿記計算的對象集合,以及一個處理在不同的打印機上打印支票和開發票的對象。也許上述對象某些已經存在,但是對於並不存在的對象,它們看起來像什麼?它們能夠提供哪些服務?它們需要哪些對象才能履行它們的義務?最終,我們會知道這個對象的構成。這是將問題分解爲對象集合的一種合理方式。
	將對象看作是服務提供者還有助於提供對象的內聚性。人們設計對象經常面臨一個問題爲將過多的功能都塞在一個對象中。例如將一個對象設計爲了解所有的格式和打印技術。我們可以拆分成多個,比如一個對象可以是所有可能的支票排版的目錄,它可以被用來查詢有關如何打印一張支票的信息,另一個對象可以是一個通用的打印接口,它知道有關所有不同類型的打印機的信息(但是不包含任何有關簿記的內容,它更應該是一個需要購買而不是自己編寫的對象);第三個對象通過調用另外兩個都系的服務來完成打印任務。在良好的面向對象設計中,每個對象都可以很好地完成一項任務,但是它並不試圖做更多的事。
	將對象作爲服務提供者不僅在設計中非常有用,而且當其他人試圖理解你的代碼或重用時,如果他們看出了這個對象所能提供的服務的價值,會使調整對象以適應其設計的過程變得簡單得多
4、被隱藏的具體實現
	程序開發人員角色一般分爲類創建者(創建新數據類型的程序員)和客戶端程序員(那些在其應用中使用數據類型的類消費者)
	隱藏的部分一般都是對象內部脆弱的部分,很容易被粗心或不知內情的程序員毀壞,隱藏將實現隱藏起來可以減少程序bug。
	在任何相互關係中,具有關係所涉及的各方都遵守的邊界非常重要。如果希望別人不要直接操作你的類中的某些成員,需要加上訪問控制,不然所有的東西都將赤裸暴露。
	訪問控制的第一個存在原因:讓客戶端程序員無法觸及他們不應該觸及的部分——這些部分對數據類型的內部操作來說是必須的,但並不是用戶解決特定問題所需的接口的一部分。這對客戶端程序員來說其實是一項服務,因爲他們可以很容易看出哪些東西對他們來說很重要,而哪些東西可以忽略。
	訪問控制的第二個存在原因:允許庫設計者可以改變類內部的工作方式而不用擔心會影響到客戶端程序員。開發了一個簡單的應用,事後發現要改寫。如果接口和實現可以清晰地分離,那麼可以輕而易舉地完成 。
	Java用三個關鍵字在類的內部設定邊界:public、private、protected。這些訪問指定詞(access specifier)覺得了緊跟其後被定義的東西可以被誰使用。public表示 緊跟其後的元素 對任何人可用。而private表示除類型創建者和類型的內部方法之外的任何人都不能訪問的元素。private就像你與客戶端程序員之間的一堵牆,如果有人視圖訪問private成員,就會在編譯時得到錯誤信息。protected關鍵字與private作用相當,差別僅在於繼承的類可以訪問protected,而不能訪問private。
	還有一個默認的訪問權限,當沒有使用前面的任何訪問指定詞,這種權限通常被稱爲包訪問權限,類可以訪問在同一個包(庫構件)中的其他類的成員,包外,這些成員如同指定private
5、複用具體實現
	最簡單的複用就是直接使用該類的一個對象,此外,可以將那個類的一個對象置於某個新的類中。我們稱其爲“創建一個成員對象”。因爲是在使用先有的類合成新的類,所以這種概念被稱爲組合(composition),如果組合是動態的,被稱爲聚合(aggregation)。組合被視爲"has-a"(擁有),就像我們常說“汽車擁有引擎”。
	新類的成員對象常被聲明爲private,使得新類的客戶端程序員不能訪問它們。這也使得你可以在不干擾現有客戶端代碼的情況下,修改這些成員,也可以在運行時修改這些成員對象,以實現動態修改程序的行爲 。有繼承不具備的靈活性
6、繼承
	對象的觀念使得我們可以通過概念將數據和功能封裝到一起,因此可以對問題空間的觀念給出恰當的表示,而不用受制於必須使用底層機器語言。這些概念用關鍵字class來表示,它們形成了編程語言中的基本單位。
	我們通過繼承可以用現有的類爲基礎,複製它,然後通過添加和修改這個副本來創建新類。當源類(被稱爲基類、超類或父類)發出變動時,被修改的“副本“(被稱爲導出類、繼承類或子類)也會反映出這些變動。
	類型不僅僅知識描述了作用於一個對象集合上的約束條件,同時還有與其他類型直接的關係。兩個類型可以有相同的特性和行爲,但是其中一個類型可能比另一個含有更多的特性,並且可以處理更多的信息(或以不同的方式來處理消息)。繼承使用基類型和導出類型的概念表示了這種類型之間的相似性。一個基類型包含其所有導出類型所共享的特性和行爲 。可以創建一個基類型來表示系統中某些對象的核心概念。
	以垃圾回收爲例,它用來歸類散落的垃圾。“垃圾”是基類型,每一件垃圾都有重量、價值等特性,可以被切碎、熔化或分解。在此基礎上,可以通過添加額外的特性(例如瓶子有顏色)或行爲(例如鐵罐可以被磁化)導出更具體的垃圾類型。此外,某些行爲可能不同(例如紙的價值取決於類型和狀態)。可以通過使用繼承來構建一個類型層次結構,以此來表示待求解的某種類型的問題。
	另一個例子是基類是幾何形,每一個幾何形都具有尺寸、顏色、位置等,同時每一個幾何形都可以被繪製、擦除、移動和着色等。在此基礎上,可以導出(繼承出)具體的幾何形狀——圓形、正方形、三角形等——每一種都具有額外的特性和行爲,例如某些形狀可以翻轉,例如計算幾何形狀的面積。類型層次結構同時體現了幾何形狀之間的相似性和差異性。
	以同樣的術語將解決方案轉換成問題是大有裨益的,因爲不需要在問題描述和解決翻翻描述之間建立許多中間模型。通過使用對象,類型層次結構成爲了主要模型,因此,可以直接從真實世界中對系統的描述過渡到代碼對系統進行描述。
	當繼承現有類型時,也就創造了新的類型。這個新的類型不僅包括現有類型的所有成員(儘管private成員被隱藏,並且不可訪問)而且更重要的是它複製了基類的接口。也就是說,所有可以發送給基類對象的消息同時也可以發送給導出類對象。由於通過發送給類的消息的 類型 可知類的類型,所以這也就意味着導出類與基類具有相同的類型。所以“一個圓形就是一個幾何形”。通過繼承而產生的類型等價性是理解面向對象程序設計方法內涵的重要門檻。
	由於基類和導出類具有相同的基礎接口,所以伴隨此接口的必定有某些具體實現。也就是說,當對象接收到特定消息時,必須有某些代碼去執行。如果知識簡單地繼承一個類而並不做其他任何事,那麼在基類接口中的方法將會直接繼承到導出類中。這意味着導出類的對象不僅與基類擁有相同的類型,而且還擁有相同的行爲,這樣做沒什麼特別意義。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章