文章前導
軟體設計是軟體工程中至關重要的一環,涵蓋著各種關於如何建立、維護和擴展軟體系統的原則和實踐。在軟體生命週期中,設計階段的決策和選擇直接影響著最終的產品品質和效能。
本文將探討軟體設計的多個層面,包括軟體生命週期、優性的軟體特性以及軟體發展中結構化和物件導向的比較。我們將深入物件導向的核心概念,從問題領域中建立物件,到物件服務的系統邊界,再到物件封裝、透通,以及物件界面、抽象和多型的應用。
最終,我們將討論物件組合的概念,這是在建立強大、靈活且可擴展的軟體系統時不可或缺的一環
無論您是軟體開發新手還是經驗豐富的工程師,本文將為您提供有價值的見解,幫助您更好地理解和應用軟體設計的原則和技巧。讓我們開始探索軟體設計的奧妙之處吧
軟體設計
軟體生命週期
● 一個軟體的開發一般會經歷以下這幾個階段
A. 軟體分析:
這一步的重點在 分析問題領域,了解並頗析需求方,並且預估部份可拓展性
「問題領域」後面小節有說明
B. 軟體設計:
確定軟體架構(或者是要使用的架構),並將整個 專案劃分成大大小小的多個子系統,設計每個子系統的具體細節
C. 軟體開發:
可以到這一步再決定開發的程式語言,並實現設計時的藍圖
D. 軟體測試:
實做單元測試、整合測試、系統測試、性能測試… 等等
E. 軟體佈署:
可以使用 CICD 上架各種不同平台
D. 軟體維護(維運):
修復軟體中的 Bug,當使用者有新需求、修改需求時可以不影響整體架構來達成需求
優質的軟體特性
● 而優良的軟體開發應該具備以下這幾個特性(以下提出幾個重點,一個優秀的軟體,它們的特性都會互交)
● 高內聚:每個子系統完成特定功能,不同子系統之間 不會有重複功能
在設計高內句的淚的同時,也要注意到子系統粒度不要過大,否則不易於維護
A. 可重用性:減少軟體程式的重複開發
B. 可維護性:當軟體需求發生變更(並不是指新需求,而是業務邏輯上的調整),可以修改局部代碼來達成需求(不會牽一髮動全身)
● 多子系統:
A. 穩定性:系統的粒度要控制,粒度越小,可被重用的機率域高,當有需要修改時,也不會影響到過多的類
B. 組合性:透過小系統的組合來達成一個大系統,這種可組合性同時帶來了軟體的重用、維護性
● 可擴充性:當接收到新需求時,應該透過 拓展的方式 來達成新需求,而不是修改已有程式碼(除了本身已有的商業邏輯錯誤)
● 低耦合:子系統之間相互獨立,並切透過抽象、界面來達成業務需求
軟體發展:結構化 vs. 物件導向
● 軟體發展 - 結構化語言:
以往非「物件導向」的程式語言,多是採用 命令式設計(像是 C 語言),會透過 SA(Structure Analysis
), SD(Structure Desgin
), SP(Structure Programming
) 相輔相成… 它(結構化)的特點在於最小單元是 方法,透過 Input, Output 來運算得到結果
對應的圖是資料流(
Data Flow
)
這種結構化命令式設計,往往導致緊耦合(並非一定)、並且不易修改
這裡的結構化結論並非一定,如果命令式設計優良,仍可達到類似物件導向的效果(可重用性高、可拓展)
e.g: 像是 C 語言的 struct 繼承、C 語言的函數指標
● 軟體發展 - 物件導向語言:
將每個需求分化,由底層開始建立(最小單元為物件),逐漸聚合為符合業務需求的軟體
其中的物件模型,就是 問題領域的物件模型(用電腦模擬現實事件的問題),它的特性如下
A. 由下至上的抽象:
就像是先畫樹葉再畫出樹幹
- 先解釋 由下:物件導向設計會分析需求然後建立一個符合需求的模型,並建立相關類別
- 再說明 至上的抽象:創建完相關類別後,將相同特性抽取出來建立一個父類抽象,這就完成了上層的抽象建立
B. 由上至下的分解:
- 建立物件模型的過程中,也同時包括了由上至下的分解
物件導向 - 核心、觀念
建立物件:問題領域
● 問題領域:用軟體來 模擬真實世界的領域(包括公司、銀行、學校… 等等領域)
● 我們在建立物件時需要注意到的是啥?內容物是啥?應該封裝哪些資訊?
這決定於你目前遇到的問題領域(問題的接觸到哪些不同的層面),你要解決哪些問題,那你應該封裝哪些資訊;
對於同一件事物的「觀點不同,所建立的物件就不同」
eg. 對於 Program Library,A 的看法是封裝的方法數量,B 的看法是大小,那就會建立兩個完全不同的物件
// 以 Library 方法的數量來封裝
class ProgramLibraryA {
int methods = 0
}
// 以 Library 的大小來封裝
class ProgramLibraryB {
int size = 0
}
那應該選擇哪個呢?
同樣!這取決於你遇到的問題領域阿!你要去判斷你目前所遇到的情況再來封裝物件
● 物件導向程式的特性如下
A. 萬物皆為物件:問題領域中的實體、概念都可以化為軟體中的物件(當然~ 每個程式語言會有些許的不同)
而如何切分大小才能保證可重用性、擴充性,則須透過經驗來判斷
B. 每個物件都是唯一:在 JVM 中提供的運行環境中,不會存在兩個相同的物件,它們各在記憶體中的唯一位置
C. 物件有屬性、行為:屬性會在一個物件的範疇內做管理,行為則是對外暴露的方法
class MySchool {
private int schoolStudentsCount = 0;
public void addStudents(int count) {
schoolStudentsCount += count;
}
}
D. 物件可以有狀態:既然物件有司有的屬性,那就可以控制該物件的狀態
class MySchool {
public static final int MAX_COUNT = 1_000;
private int schoolStudentsCount = 0;
public void addStudents(int count) {
// 控制狀態
if(schoolStudentsCount + count > MAX_COUNT) {
throw Exception();
}
schoolStudentsCount += count;
}
}
物件(
類別就像是一個模板,在 JVM 內只會存在一個(在方法區),而 物件是一個類別的實體(instance);所有的物件一定都會屬於某個類型Instance
)、類別(Class
)的差異?
物件服務:系統邊界
● 每個物件都會有特定的功能(為了解決某個問題),並對外提供解決問題的方法,並且每個子系統相互服務
● 服務邊界:就是 物件對外服務時可觸及的領域,超過這個邊界就不在服務範圍內
在設計軟體架構時,要清楚知道每個子系統的系統邊界在哪
物件封裝、透通
● 封裝:將大型實做拆分為一個個類,其好處如下● 服務邊界:就是 物件對外服務時可觸及的領域,超過這個邊界就不在服務範圍內
A. 可以隱藏系統細節(就算你裡面用了 100 個私有方法,對外仍是提供 1 個方法),使用者不必知道細節
隱藏私有屬性、方法
B. 提供系統的獨立性,內部修改並不影響外部的界面合約
隱藏大多東西,對外提供乾淨的界面
C. 適當的封裝有利於重用性
隱藏私有屬性、方法
D. 降低大型系統的風險(修復一個崩潰,結果不小心製造了 10 個崩況…之類的)
● 透通:透通得意思其實是 看不見,透通與封裝具有相同的概念… 而以下這兩句話是相同的意思
A. 物件封裝實現細節
B. 物件的實現細節對使用者是通透的 (使用者不可見的)
可以把透通記憶程玻璃,你看得見結果,但是看不見過程(那個過程就是玻璃)
物件界面、抽象與多型
● 物件界面 interface
(純抽象方法):在現實世界中界面是一個實體(像是插座、遙控、音響… 等等),但在 軟體中界面是一種抽象服務,它並 不包括實做細節;其特性如下
A. 物件導向中,界面 interface
是設計類與類之間鬆耦合的一個有效手段
B. 介面設計同時並且也保證個系統的 可拓展性、穩定性
- 在 Java 中,界面有兩種意義
- 意指系統的對外提供的服務(因為 interface 中只能有 public 方法)
- 能清晰的將系統的實現細節、界面宣告分離
● 抽象 abstract
類、方法:抽像是一種由具體到抽象、由複雜到簡潔的觀念;抽象也意味著分析事物的功能(但並不包括實現)
與界面一樣,可以用 劃分軟體設計、程式撰寫的界線
多型 & 抽象機制 & JVM
以 JVM 語言抽相機制的開發人員在開發過程中,它是 JVM 運行時提供的 動態連結機制
物件組合
● 組合就是將 多個簡單的子系統組裝,來達到業務邏輯需求的手段,它有以下優點;這裡我們回顧由上至下的分析:在建立物件模型時我們會…
A. 先分析、識別問題領域(宏觀)
B. 拆分細節、決定物件粗粒度(微觀)
● 組裝的好處如下
A. 隔離子系統個別維護
B. 隱藏系統的複雜性(封裝、透通)
C. 提高重用性
更多的物件導向設計
物件導向的設計基礎如下,如果是初學者或是不熟悉的各位,建議可以從這些基礎開始認識,打好基底才能走個更穩(在學習的時候也需要不斷回頭看)!
創建模式 Creation Patterns
● 創建模式 PK
● 創建模式 - Creation Patterns
:
創建模式用於「物件的創建」,它關注於如何更靈活、更有效地創建物件。這些模式可以隱藏創建物件的細節,並提供創建物件的機制,例如單例模式、工廠模式… 等等,詳細解說請點擊以下連結
● Singleton 單例模式 | 解說實現 | Android Framework Context Service
● Abstract Factory 設計模式 | 實現解說 | Android MediaPlayer
● Factory 工廠方法模式 | 解說實現 | Java 集合設計
● Builder 建構者模式 | 實現與解說 | Android Framwrok Dialog 視窗
● Clone 原型模式 | 解說實現 | Android Framework Intent
行為模式 Behavioral Patterns
● 行為模式 PK
● 行為模式 - Behavioral Patterns
:
行為模式關注物件之間的「通信」和「職責分配」。它們描述了一系列物件如何協作,以完成特定任務。這些模式專注於改進物件之間的通信,從而提高系統的靈活性。例如,策略模式、觀察者模式… 等等,詳細解說請點擊以下連結
● Stragety 策略模式 | 解說實現 | Android Framework 動畫
● Interpreter 解譯器模式 | 解說實現 | Android Framework PackageManagerService
● Chain 責任鏈模式 | 解說實現 | Android Framework View 事件傳遞
● Specification 規格模式 | 解說實現 | Query 語句實做
● Command 命令、Servant 雇工模式 | 實現與解說 | 物件導向設計
● Memo 備忘錄模式 | 實現與解說 | Android Framwrok Activity 保存
● Visitor 設計模式 | 實現與解說 | 物件導向設計
● Template 設計模式 | 實現與解說 | 物件導向設計
● Mediator 模式設計 | 實現與解說 | 物件導向設計
● Composite 組合模式 | 實現與解說 | 物件導向設計
● Observer 觀察者模式 | JDK Observer | Android Framework Listview
結構模式 Structural Patterns
● 結構模式 PK
● 結構模式 - Structural Patterns
:
結構模式專注於「物件之間的組成」,以形成更大的結構。這些模式可以幫助你確保當系統進行擴展或修改時,不會破壞其整體結構。例如,外觀模式、代理模式… 等等,詳細解說請點擊以下連結
● Decorate 裝飾模式 | 解說實現 | 物件導向設計
● Iterator 迭代設計 | 解說實現 | 物件導向設計