## 7.4 面向對象設計*
理解了面 向 對象的基 本 概念之后 , 就可以應 用 這些概念 來 進行面向 對 象 設 計(object-oriented design,簡稱 OOD)。 傳統的程序設計方法是結構化的自頂向下設計,其思想是將軟件系統分解為若干個功能,
每個功能都是對數據的一個操作過程。功能又可以劃分為若干個子功能,如此反復分解下去, 直至每個功能所對應的操作過程顯而易見為止。在分解功能的同時,還要考慮各功能之間的 接口。這種方法是以過程(函數)為中心的,每個函數都是一個黑盒子,函數調用者只需了 解函數的功能,無需知道實現功能的細節。
面向對象設計是以數據為中心來展開的。對于某種客觀實體的數據,考慮可能施加在數 據上的各種操作,然后將數據和操作封裝成一個黑盒子——對象。對象通過界面向外界提供 數據操作服務,服務的使用者只需了解服務接口,不必關心服務的實現細節。即使改動了對 象內部的實現細節,只要服務接口不變,所有使用該服務的程序代碼就不需要改變。同樣地, 對象作為服務提供者,也不需要考慮它的服務將被使用者如何使用,只需確保其服務能正確 處理數據即可。
因此,OOD 的中心任務就是設計各種對象,將對象的數據和行為用類定義出來。OOD 將一個復雜問題分解成一組相互協作的類,以類為設計單位可以大大減小設計的復雜性。
下面是 OOD 的一些指導準則。
描述問題
面向對象技術專家 G. Booch 提出了一種基于詞性分析的設計方法,該方法要求設計人員 從目標系統的描述出發,通過問題描述中的名詞和動詞,來發現候選對象及對象方法。因此, OOD 的第一步是要建立待解決問題的準確、無二義性的描述。問題描述應該是自然、客觀的, 不要加入人工的、主觀的因素,這是因為面向對象思想的宗旨就是按客觀世界的本來面目來 建模并開發應用系統。
找出候選對象
我們的目標是找出有助于解決問題的對象。從問題描述入手,找出問題描述中的名詞, 然后逐個考察這些名詞,看看是否合適作為對象。對象一般都包含一組相關數據項,如學生(包含學號、姓名、年齡等數據項)、課程(包含課程名、學分、教材等數據項)。而能用單 一數據表示的,或者只有單一行為的實體,一般不適合作為對象,如人數、姓名等。
注意,由于人類可以同時考慮和理解的問題數目受到大腦記憶和處理能力的制約,因此 認定的對象數目不宜過多。合適的對象通常是問題中自然出現的而非人工生硬構造的實體, 而且對象應該向外界提供足夠復雜的服務。
確定對象的數據屬性
對于認定的對象,接下來就該確定對象的數據。能確定為對象數據的信息一般都具有普遍性,即所有同類對象都擁有的數據,例如學生的學號和姓名。另外,對象數據必須對解決 問題有用,例如,學生的學號、姓名都是信息管理應用中必需的信息,而學生的發型可能就 與應用無關。注意,對象的數據可能是學號、姓名這樣的基本數據類型值,也有可能是復雜 類型的值,甚至可能是另一種對象。例如,學生選修的課程也是屬于學生對象的數據,課程 本身也是對象。
確定對象的行為屬性
認定了對象及其數據之后,接著考慮對象需要什么操作。我們從問題描述中找出動詞,它們通常描述了對象的行為。例如,“學生選修課程”中的“選修”就是學生對象的行為。對 象的方法通常使用動詞來命名。
一類常見的方法是對實例變量的讀取和設置方法。假設對象有實例變量 value,則通常應 提供 getValue 和 setValue 方法。這是因為對象數據是隱藏的,外界只能通過對象的方法來操 作對象數據。
對象的方法就是對象向外界提供的界面。界面不完善(如缺少某些方法)會使對象的使 用者無從完成工作,但也不是說向外提供的方法越多越好。對象的界面設計應當遵循恰好夠 用的原則,即在能滿足用戶需要的條件下,界面越簡潔越好。
實現對象的方法
有些方法用寥寥數行代碼就能實現,有些方法則可能需要設計復雜的算法來實現。對于復雜方法,可以利用自頂向下逐步求精方法來設計。 在方法實現過程中,可能發現一個對象與其他對象之間的新的交互,這會提示我們為類增加新方法,或者增加新的類。
迭代設計
對于復雜程序設計,沒有人能夠一次性地順利走過設計全過程。在設計過程中,經常需 要在設計、測試、增加新類或為現有類增加新方法等步驟之間循環往復。
應當多嘗試替代方案,即使一個設計方案看上去不太靈,也可以沿著該方案的方向試著 前行,看看會導致什么結果。好的設計一定是通過大量試錯而得到的,正是因為錯誤的設計 才使我們明白應該設計什么樣的系統。
最后要指出,上述基于名詞動詞分析的 OOD 方法只是一個簡單的策略,真正進行類的 設計時情況往往很復雜。究竟是否應當設計某個類并沒有絕對的設計準則,經常依賴于設計 者的經驗。和任何別的設計一樣,程序設計既是藝術也是經驗,可以通過不斷的實踐來掌握設計方法。
還要指出,對于小程序,OOD 一般起不了什么作用,說不定反而使編程變得麻煩。但當 編寫的程序越來越大,類和對象就能很好地組織程序,減少代碼量。
- 前言
- 第 1 章 計算與計算思維
- 1.1 什么是計算?
- 1.1.1 計算機與計算
- 1.1.2 計算機語言
- 1.1.3 算法
- 1.1.4 實現
- 1.2 什么是計算思維?
- 1.2.1 計算思維的基本原則
- 1.2.2 計算思維的具體例子
- 1.2.3 日常生活中的計算思維
- 1.2.4 計算思維對其他學科的影響
- 1.3 初識 Python
- 1.3.1 Python 簡介
- 1.3.2 第一個程序
- 1.3.3 程序的執行方式
- 1.3.4 Python 語言的基本成分
- 1.4 程序排錯
- 1.5 練習
- 第 2 章 用數據表示現實世界
- 2.1 數據和數據類型
- 2.1.1 數據是對現實的抽象
- 2.1.1 常量與變量
- 2.1.2 數據類型
- 2.1.3 Python 的動態類型*
- 2.2 數值類型
- 2.2.1 整數類型 int
- 2.2.2 長整數類型 long
- 2.2.3 浮點數類型 float
- 2.2.4 數學庫模塊 math
- 2.2.5 復數類型 complex*
- 2.3 字符串類型 str
- 2.3.1 字符串類型的字面值形式
- 2.3.2 字符串類型的操作
- 2.3.3 字符的機內表示
- 2.3.4 字符串類型與其他類型的轉換
- 2.3.5 字符串庫 string
- 2.4 布爾類型 bool
- 2.4.1 關系運算
- 2.4.2 邏輯運算
- 2.4.3 布爾代數運算定律*
- 2.4.4 Python 中真假的表示與計算*
- 2.5 列表和元組類型
- 2.5.1 列表類型 list
- 2.5.2 元組類型 tuple
- 2.6 數據的輸入和輸出
- 2.6.1 數據的輸入
- 2.6.2 數據的輸出
- 2.6.3 格式化輸出
- 2.7 編程案例:查找問題
- 2.8 練習
- 第 3 章 數據處理的流程控制
- 3.1 順序控制結構
- 3.2 分支控制結構
- 3.2.1 單分支結構
- 3.2.2 兩路分支結構
- 3.2.3 多路分支結構
- 3.3 異常處理
- 3.3.1 傳統的錯誤檢測方法
- 3.3.2 傳統錯誤檢測方法的缺點
- 3.3.3 異常處理機制
- 3.4 循環控制結構
- 3.4.1 for 循環
- 3.4.2 while 循環
- 3.4.3 循環的非正常中斷
- 3.4.4 嵌套循環
- 3.5 結構化程序設計
- 3.5.1 程序開發過程
- 3.5.2 結構化程序設計的基本內容
- 3.6 編程案例:如何求 n 個數據的最大值?
- 3.6.1 幾種解題策略
- 3.6.2 經驗總結
- 3.7 Python 布爾表達式用作控制結構*
- 3.8 練習
- 第 4 章 模塊化編程
- 4.1 模塊化編程基本概念
- 4.1.1 模塊化設計概述
- 4.1.2 模塊化編程
- 4.1.3 編程語言對模塊化編程的支持
- 4.2 Python 語言中的函數
- 4.2.1 用函數減少重復代碼 首先看一個簡單的用字符畫一棵樹的程序:
- 4.2.2 用函數改善程序結構
- 4.2.3 用函數增強程序的通用性
- 4.2.4 小結:函數的定義與調用
- 4.2.5 變量的作用域
- 4.2.6 函數的返回值
- 4.3 自頂向下設計
- 4.3.1 頂層設計
- 4.3.2 第二層設計
- 4.3.3 第三層設計
- 4.3.4 第四層設計
- 4.3.5 自底向上實現與單元測試
- 4.3.6 開發過程小結
- 4.4 Python 模塊*
- 4.4.1 模塊的創建和使用
- 4.4.2 Python 程序架構
- 4.4.3 標準庫模塊
- 4.4.4 模塊的有條件執行
- 4.5 練習
- 第 5 章 圖形編程
- 5.1 概述
- 5.1.1 計算可視化
- 5.1.2 圖形是復雜數據
- 5.1.3 用對象表示復雜數據
- 5.2 Tkinter 圖形編程
- 5.2.1 導入模塊及創建根窗口
- 5.2.2 創建畫布
- 5.2.3 在畫布上繪圖
- 5.2.4 圖形的事件處理
- 5.3 編程案例
- 5.3.1 統計圖表
- 5.3.2 計算機動畫
- 5.4 軟件的層次化設計:一個案例
- 5.4.1 層次化體系結構
- 5.4.2 案例:圖形庫 graphics
- 5.4.3 graphics 與面向對象
- 5.5 練習
- 第 6 章 大量數據的表示和處理
- 6.1 概述
- 6.2 有序的數據集合體
- 6.2.1 字符串
- 6.2.2 列表
- 6.2.3 元組
- 6.3 無序的數據集合體
- 6.3.1 集合
- 6.3.2 字典
- 6.4 文件
- 6.4.1 文件的基本概念
- 6.4.2 文件操作
- 6.4.3 編程案例:文本文件分析
- 6.4.4 緩沖
- 6.4.5 二進制文件與隨機存取*
- 6.5 幾種高級數據結構*
- 6.5.1 鏈表
- 6.5.2 堆棧
- 6.5.3 隊列
- 6.6 練習
- 第 7 章 面向對象思想與編程
- 7.1 數據與操作:兩種觀點
- 7.1.1 面向過程觀點
- 7.1.2 面向對象觀點
- 7.1.3 類是類型概念的發展
- 7.2 面向對象編程
- 7.2.1 類的定義
- 7.2.2 對象的創建
- 7.2.3 對象方法的調用
- 7.2.4 編程實例:模擬炮彈飛行
- 7.2.5 類與模塊化
- 7.2.6 對象的集合體
- 7.3 超類與子類*
- 7.3.1 繼承
- 7.3.2 覆寫
- 7.3.3 多態性
- 7.4 面向對象設計*
- 7.5 練習
- 第 8 章 圖形用戶界面
- 8.1 圖形用戶界面概述
- 8.1.1 程序的用戶界面
- 8.1.2 圖形界面的組成
- 8.1.3 事件驅動
- 8.2 GUI 編程
- 8.2.1 UI 編程概述
- 8.2.2 初識 Tkinter
- 8.2.3 常見 GUI 構件的用法
- 8.2.4 布局
- 8.2.5 對話框*
- 8.3 Tkinter 事件驅動編程
- 8.3.1 事件和事件對象
- 8.3.2 事件處理
- 8.4 模型-視圖設計方法
- 8.4.1 將 GUI 應用程序封裝成對象
- 8.4.2 模型與視圖
- 8.4.3 編程案例:匯率換算器
- 8.5 練習
- 第 9 章 模擬與并發
- 9.1 模擬
- 9.1.1 計算機建模
- 9.1.2 隨機問題的建模與模擬
- 9.1.3 編程案例:乒乓球比賽模擬
- 9.2 原型法
- 9.3 并行計算*
- 9.3.1 串行、并發與并行
- 9.3.2 進程與線程
- 9.3.3 多線程編程的應用
- 9.3.4 Python 多線程編程
- 9.3.5 小結
- 9.4 練習
- 第 10 章 算法設計和分析
- 10.1 枚舉法
- 10.2 遞歸
- 10.3 分治法
- 10.4 貪心法
- 10.5 算法分析
- 10.5.1 算法復雜度
- 10.5.2 算法分析實例
- 10.6 不可計算的問題
- 10.7 練習
- 第 11 章 計算+X
- 11.1 計算數學
- 11.2 生物信息學
- 11.3 計算物理學
- 11.4 計算化學
- 11.5 計算經濟學
- 11.6 練習
- 附錄
- 1 Python 異常處理參考
- 2 Tkinter 畫布方法
- 3 Tkinter 編程參考
- 3.1 構件屬性值的設置
- 3.2 構件的標準屬性
- 3.3 各種構件的屬性
- 3.4 對話框
- 3.5 事件
- 參考文獻