軟體
危機(Software Crisis)
軟體技術總是處於不斷髮展變化中,新工具、新技術相繼產生。這就要求軟體產業和軟體工程師們不停的尋求軟體設計和開發的新途徑。由於日益增長的軟體系統的複雜性和軟體產業內部愈演愈烈的競爭,這種要求變得更加緊迫。為了克服這種要求帶來的軟體危機,必須解決以下問題:
1、在系統設計中,如何表現問題的真實實體?
2、如何以開放的介面(interface)設計系統?
3、如何保證模組(module)的可重用性(reusability)和可擴充性(extensibility)?
4、如何開發能夠容忍(tolerant)未來可能的變化模組?
5、如何提高軟體的生產力和減少軟體開銷?
6、如何管理進度表?
7、如何提高軟體品質?
8、如何將軟體開發過程工業化?
當軟體產品在未完成時、未被使用時或者帶著各種各樣的錯誤發布時,問題就會出現。另外,使用者需求的改變已經成為一個重要問題。多份關於軟體實現的報告顯示,在軟體產品發布和使用之前,需要仔細進行品質評估。通常狀態評估中應該考慮的品質因素包括:
1、正確性(Correctness)
2、可維護性(Maintainability)
3、可重用性(Reusability)
4、開放性(Openness)和可解釋性(Interpretability)
5、可移植性(Portability)
6、安全性(Security)
7、完整性(Integrity)
8、方便使用性(User friendliness)
軟體演化(Software Evolution)
Ernest Tello——人工智慧領域的著名作家——將軟體技術的演化比喻為樹的生長。和樹一樣,軟體的演化具有明顯的階段性,這些階段稱為層(layer)。過去四十年中,這些層逐步被建立起來,每一個層都由前一個層發展而成。圖1顯示了這個過程。但是關於樹的比喻在遇到層的生命期的問題時失敗了。在軟體系統中,每個層都在持續的發揮作用,而在樹中,只有最上層的層才有用。
物件導向程式設計(OOP)是完成程式設計工作的新方法。自從電腦發明以來,為了適應程式複雜性的不斷增長,程式設計的方法有了戲劇性的變化。組合語言被發明出來以後,程式員們總算可以用符號表示那些機器指令,從而可以編寫更長、更複雜的程式。當程式規模繼續不停增長的時候,進階語言被引入,為程式員們提供了更多工具對付日益增加的複雜性。第一個被普遍使用的語言是FORTRAN。不過雖然FORTRAN邁出了重大的第一步,但用它寫出的代碼很難說是清晰的和容易理解的。
1960年結構化程式設計思想誕生。C和Pascal等語言都大力提倡這種程式設計的方法。結構化程式設計語言使得編寫較複雜的程式變得容易。但是,一旦某個項目達到一定規模,即使使用結構化程式設計的方法,局勢仍將變得不可控制。
在程式設計方法發展過程中,每一次重大突破都使得程式員可以應對更大的複雜性。在這條道路上邁出的每一步中,新的方法都運用和發展了以前的方法中最好的理念。今天,許多項目的規模又進一步發展。為瞭解決這個問題,物件導向程式設計方法應運而生。
在詳細介紹物件導向程式設計之前,讓我們簡單瞭解一下面向過程程式設計的方法。在面向過程的程式設計方法中,問題被看作一系列將被完成的任務,如讀、計算和列印。許多函數用於完成這些任務。問題的焦點集中於函數。圖2顯示了一個典型的面向過程的程式結構。分層分解的技術被用來確定一系列需要被完成的任務,以解決特定的問題。
面向過程程式設計的基本任務是編寫電腦執行的指令序列,並把這些指令以函數的方式組織起來。通常我們使用流程圖組織這些行為(action),並描述從一個行為到另一個行為的控制流程。
當我們集中精力開發函數的時候,很少會去注意那些被多個函數使用的資料(data)。在這些資料身上發生了什麼事情?那些使用這些資料的函數又對它們產生了什麼影響?
在多函數(multi-function)程式中,許多重要的資料被放置在全域資料區,這樣它們可以被所有的函數訪問。每個函數都可以具有它們自己的局部資料。圖3顯示了一個面向過程程式中函數和資料的關係。
物件導向程式設計模式
發明物件導向程式設計方法的主要出發點是彌補面向過程程式設計方法中的一些缺點。OOP把資料看作程式開發中的基本元素,並且不允許它們在系統中自由流動。它將資料和操作這些資料的函數緊密的連結在一起,並保護資料不會被外界的函數意外的改變。OOP允許我們將問題分解為一系列實體——這些實體被稱為對象(object),然後圍繞這些實體建立資料和函數。物件導向程式設計中的資料和函數的組織圖4所示。
一個對象的資料不能訪問其它對象的函數,而一個對象的函數可以訪問其它對象的函數。
物件導向程式設計的一些顯著的特性包括:
·程式設計的重點在於資料而不是過程;
·程式被劃分為所謂的對象;
·資料結構為表現對象的特性而設計;
·函數作為對某個對象資料的操作,與資料結構緊密的結合在一起;
·資料被隱藏起來,不能為外部函數訪問;
·對象之間可以通過函數溝通;
·新的資料和函數可以在需要的時候輕而易舉添加進來;
·在程式設計過程中遵循由下至上(bottom-up)的設計方法。
物件導向程式設計在程式設計模式中是一個新的概念,對於不同的人可能意味著不同的內容。因此在我們繼續下面的內容之前,最好給物件導向程式設計下一個定義。我們對物件導向程式設計的定義是“物件導向程式設計是一種方法,這種方法為資料和函數提供共同的獨立記憶體空間,這些資料和函數可以作為模板以便在需要時建立類似模組的拷貝。這樣的程式設計方法稱為物件導向程式設計。”
從以上定義可以看到,一個對象被認為是電腦記憶體中的一個獨立區間,在這個區間中儲存著資料和能夠訪問資料的一組操作。因為記憶體區間是相互獨立的,所以對象可以不經修改就應用於多個不同的程式中。
什麼是物件導向程式設計?
物件導向程式設計(OOP)技術汲取了結構化程式設計中好的思想,並將這些思想與一些新的、強大的理念相結合,從而給你的程式設計工作提供了一種全新的方法。通常,在物件導向的程式設計風格中,你會將一個問題分解為一些相互關聯的子集,每個子集內部都包含了相關的資料和函數。同時,你會以某種方式將這些子集分為不同等級,而一個對象就是已定義的某個類型的變數。當你定義了一個對象,你就隱含的建立了一個新的資料類型。
物件導向程式設計中的基本概念
“物件導向”作為一個術語,在不同的人群中有著不同的解釋。因此,瞭解一些在物件導向程式設計中廣泛應用的概念是必須的。本節我們討論以下這些內容:
1、對象(Object)
2、類(Class)
3、資料抽象(Data abstraction)
4、繼承(Inheritance)
5、動態綁定(Dynamic binding)
6、資料封裝(Data encapsulation)
7、多態性(Polymorphism)
8、訊息傳遞(Message passing)
對象
在一個物件導向的系統中,對象是運行期的基底實體。它可以用來表示一個人或者說一個銀行帳戶,一張資料表格,或者其它什麼需要被程式處理的東西。它也可以用來表示使用者定義的資料,例如一個向量,時間或者列表。在物件導向程式設計中,問題的分析一般以對象及對象間的自然聯絡為依據。如前所述,對象在記憶體中佔有一定空間,並且具有一個與之關聯的地址,就像Pascal中的record和C中的結構一樣。
當一個程式運行時,對象之間通過互發訊息來相互作用。例如,程式中包含一個“customer”對象和一個“account”對象,而customer對象可能會向account對象發送一個訊息,查詢其銀行帳目。每個對象都包含資料以及操作這些資料的代碼。即使不瞭解彼此的資料和代碼的細節,對象之間依然可以相互作用,所要瞭解的只是對象能夠接受的訊息的類型,以及對象返回的響應的類型,雖然不同的人會以不同的方法實現它們。
類
我們剛才提到,對象包含資料以及操作這些資料的代碼。一個對象所包含的所有資料和代碼可以通過類來構成一個使用者定義的資料類型。事實上,對象就是類類型(class type)的變數。一旦定義了一個類,我們就可以建立這個類的多個對象,每個對象與一組資料相關,而這組資料的類型在類中定義。因此,一個類就是具有相同類型的對象的抽象。例如,芒果、蘋果和桔子都是fruit類的對象。類是使用者定義的資料類型,但在一個程式設計語言中,它和內建的資料類型行為相同。比如建立一個類對象的文法和建立一個整數對象的文法一模一樣。如果fruit被定義為一個類,那麼語句
fruit mango;
就建立了一個fruit類的對象mango。
資料抽象和封裝
把資料和函數封裝在一個單獨的單元(稱為類)的行為稱為封裝。資料封裝是類的最典型特點。資料不能被外界訪問,只能被封裝在同一個類中的函數訪問。這些函數提供了對象資料和程式之間的介面。避免資料被程式直接存取的概念被稱為“資料隱藏”。
抽象指僅表現核心的特性而不描述背景細節的行為。類使用了抽象的概念,並且被定義為一系列抽象的屬性如尺寸、重量和價格,以及操作這些屬性的函數。類封裝了將要被建立的對象的所有核心屬性。因為類使用了資料抽象的概念,所以它們被稱為抽象資料類型(ADT)。
封裝
封裝機制將資料和代碼捆綁到一起,避免了外界的幹擾和不確定性。它同樣允許建立對象。簡單的說,一個對象就是一個封裝了資料和操作這些資料的代碼的邏輯實體。
在一個對象內部,某些代碼和(或)某些資料可以是私人的,不能被外界訪問。通過這種方式,對象對內部資料提供了不同層級的保護,以防止程式中無關的部分意外的改變或錯誤的使用了對象的私人部分。
繼承
繼承是可以讓某個類型的對象獲得另一個類型的對象的屬性的方法。它支援按級分類的概念。例如,知更鳥屬于飛鳥類,也屬於鳥類。就像圖5中描繪的那樣,這種分類的原則是,每一個子類都具有父類的公用特性。
在OOP中,繼承的概念很好的支援了代碼的重用性(reusability),也就是說,我們可以向一個已經存在的類中添加新的特性,而不必改變這個類。這可以通過從這個已存在的類派生一個新類來實現。這個新的類將具有原來那個類的特性,以及新的特性。而繼承機制的魅力和強大就在於它允許程式員利用已經存在的類(接近需要,而不是完全符合需要的類),並且可以以某種方式修改這個類,而不會影響其它的東西。
注意,每個子類只定義那些這個類所特有的特性。而如果沒有按級分類,每類都必須顯式的定義它所有的特性。
多態
多態是OOP的另一個重要概念。多態的意思是事物具有不同形式的能力。舉個例子,對於不同的執行個體,某個操作可能會有不同的行為。這個行為依賴於所要操作資料的類型。比如說加法操作,如果操作的資料是數,它對兩個數求和。如果操作的資料是字串,則它將串連兩個字串。
圖6示範了一個函數處理不同數量、不同類型的參數。就像某個單詞在不同的上下文中具有不同的含義。
多態機制使具有不同內部結構的對象可以共用相同的外部介面。這意味著,雖然針對不同對象的具體操作不同,但通過一個公用的類,它們(那些操作)可以通過相同的方式予以調用。多態在實現繼承的過程中被廣泛應用。
物件導向程式設計語言支援多態,術語稱之為“one interface multiple method(一個介面,多個實現)”。簡單來說,多態機制允許通過相同的介面引發一組相關但不相同的動作,通過這種方式,可以減少代碼的複雜度。在某個特定的情況下應該作出怎樣的動作,這由編譯器決定,而不需要程式員手工幹預。
在多函數程式中,許多重要的資料被聲明為全域變數,這樣它們才可以被所有的函數訪問。每個函數又可以具有它自己的局部變數。全域變數很容易被某個函數不經意之間改變。而在一個大程式中,很難分辨每個函數都使用了哪些變數。如果我們需要修改某個外部資料的結構,我們就要修改所有訪問這個資料的函數。這很容易導致bug的產生。
在結構化程式設計中,另一個嚴重的缺陷是不能很好的類比真實世界的問題。這是因為函數都是面向過程的,而不是真正的對應於問題中的各個元素。
面向過程的程式設計的一些特點如下:
·強調做(演算法);
·大程式被分隔為許多小程式,這些小程式稱為函數;
·大多數函數共用全域資料;
·資料開放的由一個函數流向另一個函數。函數把資料從一種形式轉換為另一種形式。
採用由上至下的程式設計方法。
動態綁定
綁定指的是將一個程序呼叫與相應代碼連結起來的行為。動態綁定的意思是,與給定的程序呼叫相關聯的代碼只有在運行期才可知。它與多態和繼承的聯絡極為緊密。一個多態引用的函數調用決定於這個引用的動態類型。
考慮圖6中的“draw”方法。通過繼承,每個對象都具備了這個過程。但是,對於不同的對象它的演算法是不同的,因此,draw過程必須在每一個類中重新定義。在運行期,當前引用對象所對應的代碼將被調用。
訊息傳遞
一個物件導向的程式由許多個物件組成,這些對象之間需要相互溝通。因此,在物件導向程式設計語言中,程式設計的主要步驟如下:
1、建立類,這些類定義了對象及其行為;
2、由類定義建立對象;
3、建立對象之間的通訊。
對象之間通過收發資訊相互溝通,這一點類似於人與人之間的資訊傳遞。資訊傳遞的概念使得真實世界的直接類比更易於和建立系統交流。
對於某個特定對象來說,訊息就是請求執行某個過程,因此,訊息的接收對象會調用一個函數(過程),以產生預期的結果。傳遞的訊息的內容包括接收訊息的對象的名字,需要調用的函數的名字,以及必要的資訊。
對象就有一個生命週期。它們可以被建立和銷毀。只要對象正處於其生存期,就可以與其進行通訊。
OOP的優點
OOP具有許多優點,無論是對於程式設計者或者使用者來說都是如此。物件導向為軟體產品擴充和品質保證中的許多問題提供瞭解決辦法。這項技術能夠大大提高程式員的生產力,並可提高軟體的品質以及降低其維護費用。其主要的優點陳列於下:
1、通過繼承,我們可以大幅減少多餘的代碼,並擴充現有代碼的用途;
2、我們可以在標準的模組上(這裡所謂的“標準”指程式員之間彼此達成的協議)構建我們的程式,而不必一切從頭開始。這可以減少軟體開發時間並提高生產效率;
3、資料隱藏的概念協助程式員們保護程式免受外部代碼的侵襲;
4、允許一個對象的多個執行個體同時存在,而且彼此之間不會相互幹擾;
5、允許將問題空間中的對象直接映射到程式中;
6、基於對象的工程可以很容易的分割為獨立的部分;
7、資料中心設計方法允許我們抓住可實現模型的更多細節;
8、物件導向的系統很容易從小到大逐步升級;
9、對象間通訊所使用的訊息傳遞技術與外部系統介面部分的描述更簡單;
10、更便於控制軟體複雜度。
當需要將以上所說的所有特性有機的結合於一個物件導向系統中,它們之間的相對重要性就取決於工程的類型和程式員的喜好。為了獲得上述的某些優勢,必須考慮很多事情。例如,物件程式庫必須可以被重用。技術還在不停的發展,現有的產品也會很快的更新換代。如果重用沒有能夠實現,那麼就需要進行嚴格的控制和管理。
便於使用的開發軟體往往難以編寫。物件導向程式設計工具有望解決這個問題。
物件導向程式設計語言
物件導向技術並不是某個特定語言的特權。如同結構化程式設計一樣,OOP概念可以在很多語言比如C和Pascal中實現。但是,當程式越來越大時,程式設計工作會變得拙劣而混亂。而一個支援OOP概念的程式設計語言則可以讓一切變得簡單。
一個語言必須支援幾個主要的OOP概念才能稱其是物件導向的。根據所支援的OOP特性,語言可以分為以下兩類:
1、基於對象的程式設計語言;
2、物件導向的程式設計語言。
基於對象的程式設計語言僅支援封裝和對象辨識。
一個物件導向的程式設計語言所要支援的重要特性如下:
·資料封裝
·資料隱藏和訪問機制
·對象的自動初始化和清除
·操作符重載
支援對象風格程式設計的語言稱為基於對象的程式設計語言。它們不支援繼承和動態綁定。
Ada就是一個典型的基於對象的程式設計語言。
物件導向的程式設計不僅僅包含基於對象程式設計的特性,還支援繼承和動態綁定。
OOP的應用
OOP最有前途的應用領域如下:
1、即時系統;
2、模擬和建模;
3、面相對象資料庫;
4、超文本、超媒體和擴充文本;
5、AI和專家系統;
6、神經網路和並行程式設計;
7、決策支援和辦公自動化系統;
8、CIM/CAM/CAD系統。