物件導向-物件導向思想
昔人已乘黃鶴去,此地空餘黃鶴樓
簡介:物件導向-物件導向思想。
一、三大特性
封裝
利用抽象資料型別將資料和基於資料的操作封裝在一起,使其構成一個不可分割的獨立實體。資料被保護在抽象資料型別的內部,儘可能地隱藏內部的細節,只保留一些對外的介面使其與外部發生聯絡。使用者無需關心物件內部的細節,但可以通過物件對外提供的介面來訪問該物件。
優點:
- 減少耦合:可以獨立地開發、測試、優化、使用、理解和修改
- 減輕維護的負擔:可以更容易被理解,並且在除錯的時候可以不影響其他模組
- 有效地調節效能:可以通過剖析來確定哪些模組影響了系統的效能
- 提高軟體的可重用性
- 降低了構建大型系統的風險:即使整個系統不可用,但是這些獨立的模組卻有可能是可用的
以下 Person 類封裝 name、gender、age 等屬性,外界只能通過 get() 方法獲取一個 Person 物件的 name 屬性和 gender 屬性,而無法獲取 age 屬性,但是 age 屬性可以供 work() 方法使用。
注意到 gender 屬性使用 int 資料型別進行儲存,封裝使得使用者注意不到這種實現細節。並且在需要修改 gender 屬性使用的資料型別時,也可以在不影響客戶端程式碼的情況下進行。
1 public class Person {
2
3 private String name;
4 private int gender;
5 private int age;
6
7 public String getName() {
8 return name;
9 }
10
11 public String getGender() {
12 return gender == 0 ? "boy" : "girl";
13 }
14
15 public void work() {
16 if (18 <= age && age <= 50) {
17 System.out.println(name + " is working very hard!");
18 } else {
19 System.out.println(name + " can't work any more!");
20 }
21 }
22 }
繼承
繼承實現了 IS-A 關係,例如 Cat 和 Animal 就是一種 IS-A 關係,因此 Cat 可以繼承自 Animal,從而獲得 Animal 非 private 的屬性和方法。
繼承應該遵循里氏替換原則,子類物件必須能夠替換掉所有父類物件。
Cat 可以當做 Animal 來使用,也就是說可以使用 Animal 引用 Cat 物件。父類引用指向子類物件稱為 向上轉型 。
Animal animal = new Cat();
多型
多型分為編譯時多型和執行時多型:
- 編譯時多型主要指方法的過載
- 執行時多型指程式中定義的物件引用所指向的具體型別在執行期間才確定
執行時多型有三個條件:
- 繼承
- 覆蓋(重寫)
- 向上轉型
下面的程式碼中,樂器類(Instrument)有兩個子類:Wind 和 Percussion,它們都覆蓋了父類的 play() 方法,並且在 main() 方法中使用父類 Instrument 來引用 Wind 和 Percussion 物件。在 Instrument 引用呼叫 play() 方法時,會執行實際引用物件所在類的 play() 方法,而不是 Instrument 類的方法。
1 public class Instrument {
2
3 public void play() {
4 System.out.println("Instument is playing...");
5 }
6 }
1 public class Wind extends Instrument {
2
3 public void play() {
4 System.out.println("Wind is playing...");
5 }
6 }
1 public class Percussion extends Instrument {
2
3 public void play() {
4 System.out.println("Percussion is playing...");
5 }
6 }
1 public class Music {
2
3 public static void main(String[] args) {
4 List<Instrument> instruments = new ArrayList<>();
5 instruments.add(new Wind());
6 instruments.add(new Percussion());
7 for(Instrument instrument : instruments) {
8 instrument.play();
9 }
10 }
11 }
1 輸出:
2 Wind is playing...
3 Percussion is playing...
二、設計原則
設計模式參考連結:https://www.cnblogs.com/taojietaoge/p/10317701.html
S.O.L.I.D
簡寫 | 全拼 | 中文翻譯 |
---|---|---|
SRP | The Single Responsibility Principle | 單一責任原則 |
OCP | The Open Closed Principle | 開放封閉原則 |
LSP | The Liskov Substitution Principle | 里氏替換原則 |
ISP | The Interface Segregation Principle | 介面分離原則 |
DIP | The Dependency Inversion Principle | 依賴倒置原則 |
1. 單一責任原則
修改一個類的原因應該只有一個。
換句話說就是讓一個類只負責一件事,當這個類需要做過多事情的時候,就需要分解這個類。
如果一個類承擔的職責過多,就等於把這些職責耦合在了一起,一個職責的變化可能會削弱這個類完成其它職責的能力。
2. 開放封閉原則
類應該對擴充套件開放,對修改關閉。
擴充套件就是新增新功能的意思,因此該原則要求在新增新功能時不需要修改程式碼。
符合開閉原則最典型的設計模式是裝飾者模式,它可以動態地將責任附加到物件上,而不用去修改類的程式碼。
3. 里氏替換原則
子類物件必須能夠替換掉所有父類物件。
繼承是一種 IS-A 關係,子類需要能夠當成父類來使用,並且需要比父類更特殊。
如果不滿足這個原則,那麼各個子類的行為上就會有很大差異,增加繼承體系的複雜度。
4. 介面分離原則
不應該強迫客戶依賴於它們不用的方法。
因此使用多個專門的介面比使用單一的總介面要好。
5. 依賴倒置原則
高層模組不應該依賴於低層模組,二者都應該依賴於抽象;
抽象不應該依賴於細節,細節應該依賴於抽象。
高層模組包含一個應用程式中重要的策略選擇和業務模組,如果高層模組依賴於低層模組,那麼低層模組的改動就會直接影響到高層模組,從而迫使高層模組也需要改動。
依賴於抽象意味著:
- 任何變數都不應該持有一個指向具體類的指標或者引用;
- 任何類都不應該從具體類派生;
- 任何方法都不應該覆寫它的任何基類中的已經實現的方法。
其他常見原則
除了上述的經典原則,在實際開發中還有下面這些常見的設計原則。
簡寫 | 全拼 | 中文翻譯 |
---|---|---|
LOD | The Law of Demeter | 迪米特法則 |
CRP | The Composite Reuse Principle | 合成複用原則 |
CCP | The Common Closure Principle | 共同封閉原則 |
SAP | The Stable Abstractions Principle | 穩定抽象原則 |
SDP | The Stable Dependencies Principle | 穩定依賴原則 |
1. 迪米特法則
迪米特法則又叫作最少知識原則(Least Knowledge Principle,簡寫 LKP),就是說一個物件應當對其他物件有儘可能少的瞭解,不和陌生人說話。
2. 合成複用原則
儘量使用物件組合,而不是通過繼承來達到複用的目的。
3. 共同封閉原則
一起修改的類,應該組合在一起(同一個包裡)。如果必須修改應用程式裡的程式碼,我們希望所有的修改都發生在一個包裡(修改關閉),而不是遍佈在很多包裡。
4. 穩定抽象原則
最穩定的包應該是最抽象的包,不穩定的包應該是具體的包,即包的抽象程度跟它的穩定性成正比。
5. 穩定依賴原則
包之間的依賴關係都應該是穩定方向依賴的,包要依賴的包要比自己更具有穩定性。
昔人已乘黃鶴去
此地空餘黃鶴樓