天天看點

面向對象技術

對象是面向對象的程式設計的核心,它由描述狀态的屬性(變量)和用來實作對象行為的方法(函數)組成,完成了從資料模型到處理模型的結合與統一。面向對象方法論的出發點和基本原則是盡可能模拟人類習慣的思維方式,使開發軟體的方法與過程盡可能接近人類認識世界解決問題的方法與過程;也就是使描述問題的問題空間(也稱為問題域)與實作解法的解空間(也稱為求解域)在結構上盡可能一緻。這樣就解決了系統在分析過程中獲得的分析模型與設計過程中所獲得的設計模型進行轉換時,由于了解上的差異而造成的系統不穩定性。面向對象方法論中産生的設計模型是分析模型的進一步完善和細化,使得模型之間的轉換成為一種平滑的過渡。

面向對象技術

1.面向對象與面向過程的差別

在軟體工程裡,面向對象是繼結構化革命之後的又一次軟體開發方式革命。面向對象的主要思想是基于抽象資料類型的(Abstract Data Type, ADT):在結構化程式設計過程中,人們發現把某種資料結構和用于操縱它的各種操作以某種子產品化方式綁定到一起會非常友善,使用這種方式進行程式設計時資料結構的接口是固定的。如果對抽象資料類型進一步抽象,就會發現把這種資料類型的執行個體當作一個具體的東西、事物、對象,就可以引發人們對程式設計過程中怎樣看待所處理的問題的一次大的改變。

是以對于面向對象而言,系統是互動對象的集合,對象與人或其它對象互動,對象發送與響應消息。

面向過程(Process Oriented)這個詞是在面向對象(Object Oriented)出現之後為與之相對而提出的。它在以前基本被叫做“結構化程式設計”。早期的程式設計,大量使用共享變量(全局變量)和使用三種基本流程(順序、選擇、重複)來實作,每種語言都提供這些基本控制結構的實作方式,并提供把資料通路局部化的能力,以及某種形式的子產品化/分别編譯機制。在這些基礎上,人們所進行的程式設計活動基本是通過寫用于不同目的的功能函數/過程來實作,這也是“面向過程”的由來。

是以對于面向過程而言,系統是過程的集合,過程與資料實體互動,過程接受輸入并産生輸出。

面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實作,使用的時候一個一個依次調用就可以了。面向對象是把構成問題事務分解成各個對象,建立對象的目的不是為了完成一個步驟,而是為了描叙某個事物在整個解決問題的步驟中的行為。

例如五子棋遊戲,面向過程的設計思路就是首先分析問題的步驟:

1)、開始遊戲,

2)、黑子先走,

3)、繪制畫面,

4)、判斷輸赢,

5)、輪到白子,

6)、繪制畫面,

7)、判斷輸赢,

8)、傳回步驟2,

9)、輸出最後結果。

把上面每個步驟用分别的函數來實作,問題就解決了。而面向對象的設計則是從另外的思路來解決問題。整個五子棋可以分為:

1)、黑白雙方,這兩方的行為是一模一樣的,

2)、棋盤系統,負責繪制畫面,

3)、規則系統,負責判定諸如犯規、輸赢等。

  第一類對象(玩家對象)負責接受使用者輸入,并告知第二類對象(棋盤對象)棋子布局的變化,棋盤對象接收到了棋子的變化就要負責在螢幕上面顯示出這種變化,同時利用第三類對象(規則系統)來對棋局進行判定。

  可以明顯地看出,面向對象是以功能來劃分問題,而不是步驟。同樣是繪制棋局,這樣的行為在面向過程的設計中分散在了總多步驟中,很可能出現不同的繪制版本,因為通常設計人員會考慮到實際情況進行各種各樣的簡化。而面向對象的設計中,繪圖隻可能在棋盤對象中出現,進而保證了繪圖的統一。

功能上的統一保證了面向對象設計的可擴充性。比如我要加入悔棋的功能,如果要改動面向過程的設計,那麼從輸入到判斷到顯示這一連串的步驟都要改動,甚至步驟之間的循序都要進行大規模調整。如果是面向對象的話,隻用改動棋盤對象就行了,棋盤系統儲存了黑白雙方的棋譜,簡單回溯就可以了,而顯示和規則判斷則不用顧及,同時整個對對象功能的調用順序都沒有變化,改動隻是局部的。

需要說明的是,面向過程和面向對象是解決問題的思考方式,即使是面向對象的方法也是含有面向過程的思想。

2.面向對象的重要概念

面向對象的軟體工程将以面向對象視角,采用面向對象的分析設計方法來解決搭建軟體系統的問題,是以對于面向對象概念的了解和把握将直接影響面向對象系統的構成品質。下面将簡單介紹一下面向對象中幾個非常重要的概念。

2.1對象(Object)

現實世界中,随處可見的一種事物就是對象,對象是事物存在的實體,如人類、書桌、計算機、高樓大廈等。人類解決問題的方式總是将複雜的事物簡單化,于是就會思考這些對象都是由哪些部分組成的。通常都會将對象劃分為兩個部分,即動态部分與靜态部分。靜态部分,顧名思義就是不能動的部分,這個部分被稱為“屬性”,任何對象都會具備其自身屬性,如一個人,它包括高矮、胖瘦、性别、年齡等屬性。然而具有這些屬性的人會執行哪些動作也是一個值得探讨的部分,這個人可以哭泣、微笑、說話、行走,這些是這個人具備的行為(動态部分),人類通過探讨對象的屬性和觀察對象的行為了解對象。

面向對象方法學中的對象是由描述該對象屬性的資料(資料結構)以及可以對這些資料施加的所有操作封裝在一起構成的統一體。這個封裝體有可以唯一地辨別它的名字,而且向外界提供一組服務。從程式設計者來看,對象是一個程式子產品;從使用者來看,對象為他們提供所希望的行為或服務;從對象自身來看,這種服務或行為通常稱為方法。

要想深刻了解對象的特點,就必須明确對象的下述特點:

• 以資料為中心。

所有施加在對象上的操作都基于對象的屬性,這樣保證對象内部的資料隻能通過對象的私有方法來通路或處理,這就保證了對這些資料的通路或處理,在任何時候都是使用統一的方法進行的。

• 對象是主動的。

對象向外提供的方法是自身向外提供的服務。對于資料的提供不是被動的,而是根據自身的特點及接收發來的消息進行處理後向外回報資訊。

• 實作了資料封裝。

使用對象時隻需知道它向外界提供的接口形式而無須知道它的内部實作算法。不僅使得對象的使用變得非常簡單、友善,而且具有很高的安全性和可靠性,實作了資訊隐藏原則。

• 對象對自己負責

對象可以通過父類得知自己的類型,對象中的資料能夠告訴自己它的狀态如何,而對象中的代碼能夠使它正确工作。

• 子產品獨立性好。

對象中的方法都是為同一職責服務的,子產品的内聚程度高。

2.2類(Class)

我們一般習慣于把有相似特征的事物歸為一類。在面向對象的技術中,把具有相同屬性和相同操作的一組相似對象也歸為一“類”。類是對象的模闆。即類是對一組有相同屬性和相同操作的對象的定義,一個類所包含的方法和屬性描述一組對象的共同屬性和行為。類是在對象之上的抽象,對象則是類的具體化,是類的執行個體。類可有其子類,也可有其它類,形成類的層次結構。

例如:三個圓心位置、半徑大小和顔色均不相同的圓,是三個不同的對象。但是,它們都有相同的屬性(圓心坐标、半徑、顔色)和相同的操作(計算面積、繪制圖形等等)。是以,它們是同一類事物,可以用“Circle類”來定義。

執行個體(Instance)就是由某個特定的類所描述的一個具體的對象。

2.3消息(message)

消息就是向對象發出的服務請求。它包含了提供服務的對象辨別、服務(方法)辨別、輸人資訊和回答資訊等。

面向對象方法的一個原則就是通過消息進行對象之間的通信。初學面向對象方法的人往往把消息等同于函數調用,事實上兩者之間存在差別。消息可以包括同步消息和異步消息,如果消息是異步的,則一個對象發送消息後,就繼續自己的活動,不等待消息接收者傳回控制,而函數調用往往是同步的,消息的發送者要等待接收者傳回。

2.4封裝(encapsulation)

封裝性是面向對象的主要特征之一,它是一種資訊隐蔽技術,它展現于類的說明。封裝使資料和加工該資料的方法(函數)封裝為一個整體,使得使用者隻能見到對象的外部特性(對象能接受哪些消息,具有哪些處理能力),而對象的内部特性(儲存内部狀态的私有資料和實作加工能力的算法)對使用者是隐蔽的。封裝的目的在于把對象的設計者和對象的使用者分開,使用者不必知曉行為實作的細節,隻須用設計者提供的接口來通路該對象。對象具有封裝性的條件如下:

(1)有一個清晰的邊界。所有私有資料和實作操作的代碼都被封裝在這個邊界内,從外面看不見,更不能直接通路。

(2)有确定的接口(即協定)。這些接口就是對象可以接受的消息,隻能通過向對象發送消息來使用它。

(3)受保護的内部實作。實作對象功能的細節(私有資料和代碼)不能在定義該對象的類的範圍外通路。

2.5繼承(Inheritance)

繼承性是子類自動共享父類之間資料和方法的機制。它由類的派生功能展現。一個類直接繼承其它類的全部描述,同時可修改和擴充。三種繼承方式:

第一,繼承能夠直接獲得已有的性質和特征,而不必重複定義它們。

第二,在子類中可以增加或重新定義所繼承的屬性或方法,如果是重新定義,則稱為覆寫(override)。

第三,與覆寫很類似的一個概念是重載(overload ),重載指的是一個類中有多個同名的方法,重載關心的隻是參數,有參無參,參數類型不同,參數數量不同,不同類型的參數順序不同,都可以實作方法的重載。舉個例子:

public class Shape 

{

public static void main(String[] args){

Triangle tri = new Triangle();

System.out.println("Triangle is a type of shape? " + tri.isShape());// 繼承

Rectangle Rec = new Rectangle();

Shape shape2 = Rec;

System.out.println("My shape has " + shape2.getSides(Rec) + " sides."); //重載

}

public boolean isShape(){

return true;

}

public int getSides(){

return 0 ;

}

public int getSides(Triangle tri){ //重載

return 3 ;

}

public int getSides(Rectangle rec){ //重載

return 4 ;

}

}

class Triangle extends Shape 

{

public int getSides() { //重寫

return 3;

}

}

class Rectangle extends Shape 

{

public int getSides(int i) { //重載

return i;

}

}      

繼承具有傳遞性。繼承分為單繼承(一個子類隻有一父類,使得類等級成為樹形結構)和多重繼承(一個類有多個父類,多重繼承的類可以組合多個父類的性質構成所需要的性質)。類的對象是各自封閉的,如果沒繼承性機制,則類對象中資料、方法就會出現大量重複。繼承不僅支援系統的可重用性,而且還促進系統的可擴充性。

一個類實際上繼承了它所在的類等級中在它上層的全部基類的所有描述。也就是說,屬于某類的對象除了具有該類所描述的性質外,還具有類等級中該類上層全部基類描述的一切性質。

多繼承雖然比較靈活,但多繼承可能會帶來“命名沖突”的問題。同時,對象的本質問題模糊不清。例如,我們要實作會飛的汽車,我們可以繼承汽車類和飛機類,但我們的飛行汽車已經成了雜交品種,分不出到底是車還是飛行器了。這裡就可以知道為什麼C#和JAVA都不支援多重繼承基類了。避免雜交,減少耦合。當然,如JAVA給出了解決多繼承的方法,用接口和抽象類。

2.6多态性(Polymorphism)

多态性是允許不同類的對象對同一消息做出響應。即同一消息可以根據發送對象的不同而采用多種不同的行為方式。(發送消息就是函數調用)

利用多态性使用者可發送一個通用的資訊,而将所有的實作細節都留給接受消息的對象自行決定,這樣,同一消息即可調用不同的方法。例如:print消息被發送給一個圖或表時調用的列印方法與将同樣的Print消息發送給一個正文檔案而調用的列印方法會完全不同。多态性的實作受到繼承性的支援,利用類繼承的層次關系,把具有通用功能的協定存放在類層次中盡可能高的地方,而将實作這一功能的不同方法置于較低層次,這樣,在這些低層次上生成的對象就能給通用消息以不同的響應。在面向對象程式設計中可通過在派生類中重定義基類函數來實作多态性。從一定角度來看,封裝和繼承幾乎都是為多态而準備的。

在提到多态的同時,不得不提到抽象類和接口,因為多态的實作并不依賴具體類,而是依賴于抽象類(abstract class)和接口(interface)。

抽象類(abstract class):對具體對象的最高抽象,這個對象擁有自己的最基本特征。在面向對象的概念中,我們知道所有的對象都是通過類來描繪的,但是反過來卻不是這樣。并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的資訊來描繪一個具體的對象,這樣的類就是抽象類。抽象類往往用來表征我們在對問題領域進行分析、設計中得出的抽象概念,是對一系列看上去不同,但是本質上相同的具體概念的抽象。比如我們進行一個圖形編輯軟體的開發,就會發現問題領域存在着圓、三角形這樣一些具體概念,它們是不同的,但是它們又都屬于形狀這樣一個概念,形狀這個概念在問題領域是不存在的,它就是一個抽象概念。

在面向對象領域,抽象類主要用來進行類型隐藏。我們可以構造出一個固定的一組行為的抽象描述,但是這組行為卻能夠有任意個可能的具體實作方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實作則表現為所有可能的派生類。子產品可以操作一個抽象體。由于子產品依賴于一個固定的抽象體,是以它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴充此子產品的行為功能。

接口(interface):是某類行為或功能的抽象。是一種開關或者是契約。

如果一個抽象類中的所有方法都是抽象的,就可以将這個類用借口定義。借口是一個特殊的抽象類,沒有變量和方法實作。

接口隔離原則,指的是不要把多個功能全部都集中在一個接口裡面。接口實作的功能要相對單一;衍生開來可以得到另外一個結論:對一組或者稱一系列功能的實作,盡量定義相對功能單一的小子產品來實作這一組功能。這其實也是解耦和的展現。

是以,接口抽象行為,抽象類抽象對象;用抽象類來實作接口,子類再繼承基類;抽象類和接口本質上都是是系統的最高抽象。

如上飛行汽車的例子,設定我們對于問題領域的了解是:飛行汽車在概念本質上是汽車,同時它有具有飛行的功能。我們該如何來設計、實作來明确的反映出我們的意思呢? abstract class在Java語言中表示一種繼承關系,而繼承關系在本質上是"is a"關系。是以對于汽車這個概念,我們應該使用abstarct class方式來定義。另外,飛行汽車又具有飛行功能,說明它又能夠完成飛行概念中定義的行為,是以飛行概念可以通過interface方式定義,interface表示的是"like a"關系。代碼如下:

interface IFlyable

{

void Fly();

}

public abstract class Car

{

public abstract string Wheel

{

get;

set;

}

public virtual void Move()

{

Console.WriteLine("車移動了");

}

}

public sealed class FlyCar extends Car implements IFlyable

{

private string wheel = string.Empty;

public override string Wheel

{

get

{

return wheel;

}

set

{

wheel = value;

}

}

public void Fly()

{

base.Move();

Console.WriteLine("汽車起飛成功!");

}

}

//在這裡應用任何模式都很簡單了

static void Main(string[] args)

{

FlyCar c = new FlyCar();

((IFlyable)c).Fly();

((Car)c).Move();

}      

-------------------------------------------------------------------------------------------------------------------------------------

面向對象無處不在,弄懂它很重要。

轉載需注明轉載字樣,标注原作者和原博文位址。

面向對象技術

繼續閱讀