一、面向對象設計的三個基本要素
面向對象的三個基本特征是:封裝、繼承、多態。
1. 封裝性
封裝是一種信息隱蔽技術,他體現於類的說明,是都西昂重要的特性。
封裝使得數據和操作數據的方法封裝成一個整體,想成為獨立性很強的模塊,使得用戶只能看到對象的外部特征,內部是看不到的。
例:屬性私有,get/set方法,有參構造 ,方法
2.繼承性
繼承是一種由已有類創建子類的機制,利用繼承,可以先創建一個共有屬性的一般類,根據這個類再創建具有特殊屬性的子類,被繼承的類成為父類,當然子類也可以成為父類來繼續向下擴展。
例:子承父類
3.多態
同一個信息被不同的對象接收到時可能產生不同的行為,這就是多態性。有繼承(接口)有重寫,父類引用指向子類對象,就會產生多態。多態可以改善程序的組織架構,提高程序的可擴展性。
例:父類指向子類對象,子類重寫父類方法
二、面向對象設計的五個基本設計原則
面向對象設計的五個基本設計原則是:單一職責原則、開放封閉原則、里氏替換原則、依賴倒置原則、接口隔離原則
1.單一職責原則
就一個類而言,應該只專注於做一件事和僅有一個引起它變化的原因。
也可以理解為引用變化的原因,當你發現有兩個變化會要求我們修改這個類,那么你就要考慮撤分這個類了。因為職責是變化的一個軸線,當需求變化時,該變化會反映類的職責的變化。
“就像一個人身兼數職,而這些事情相互關聯不大,甚至有沖突,那他就無法很好的解決這些職責,應該分到不同的人身上去做才對。”
interface Modem//貓 { public void dial(string pno);//撥號 public void hangup();//掛斷 public void send(char c);//發送 public void recv();//接受 } //應改為 interface DataChannel//數據通道 { public void send(char c); public void recv(); } interface Connection//鏈接 { public void dial(string pno); public void hangup(); }
優點:消除耦合,減小因需求變化引起代碼僵化
2·開放封閉原則
其核心思想是:軟件實體應該是可擴展的,而不可修改的。也就是,對擴展開放,對修改封閉。開放封閉原則主要體現在兩個方面 1、對擴展開放,意味着有新的需求或者變化時,可以對現有代碼進行擴展,以適應新的情況。 2、對修改封閉,意味着一旦設計完成,就可以獨立完成其工作,而不要對其進行任何嘗試的修改。
public interface Bark { public void bark(); } public class Awaw implements Bark{ @Override public void bark() { System.out.println("嗷嗷~~"); } } public class Zhazha implements Bark{ @Override public void bark() { System.out.println("喳喳~~"); } } public abstract class Bird { //聲明屬性 private Bark bark;//接口的對象 //設置set屬性 public void setBark(Bark bark) { this.bark = bark; } /** * 鳥叫的方法 */ public void birdBark(){ bark.bark(); } } public class Test { public static void main(String[] args) { //測試 //聲明鳥的叫聲 Bark awaw = new Awaw(); Bark zhazha = new Zhazha(); //bird對象 Bird rocketBird = new RocketBird(); rocketBird.setBark(awaw); Bird splitBird = new SplitBird(); splitBird.setBark(zhazha); } }
優點:
1、降低程序各部分之間的耦合性,使程序模塊互換成為可能; 2、使軟件各部分便於單元測試,通過編制與接口一致的模擬類(Mock),可以很容易地實現軟件各部分的單元測試; 3、利於實現軟件的模塊的呼喚,軟件升級時可以只部署發生變化的部分,而不會影響其它部分;
3·里氏替換原則
核心思想:子類必須能夠替換其父類。這一思想體現為對繼承機制的約束規范,只有子類能夠替換父類時才能保證系統在運行期內識別子類,這是保證繼承復用的基礎。在父類和子類的具體行為中,必須嚴格把握繼承層次中的關系和特征,將父類替換為子類,程序的行為不會發生任何變化。同時,這一約束反過來則是不成立的,子類可以替換父類,但是父類不一定能替換子類。
對於這個原則,通俗一些的理解就是,父類的方法都要在子類中實現或者重寫。
public abstract class Bird { /** * 飛的方法 */ void fly(){ System.out.println("彈跳-飛"); } /** * 叫的方法 */ void call(){ System.out.println("嗷~!"); } /** * 攻擊的抽象方法 */ abstract void attack(); } public class RocketBird extends Bird { @Override void attack() { System.out.println("加速沖刺"); } } public class SplitBird extends Bird{ @Override void attack() { System.out.println("分裂攻擊"); } } public class Test { public static void main(String[] args) { Bird splitBird = new SplitBird(); Bird rocketBird = new RocketBird(); splitBird.attack(); rocketBird.attack(); } }
優點:
1、保證系統或子系統有良好的擴展性。只有子類能夠完全替換父類,才能保證系統或子系統在運行期內識別子類就可以了,因而使得系統或子系統有了良好的擴展性。 2、實現運行期內綁定,即保證了面向對象多態性的順利進行。這節省了大量的代碼重復或冗余。避免了類似instanceof這樣的語句,或者getClass()這樣的語句,這些語句是面向對象所忌諱的。 3、有利於實現契約式編程。契約式編程有利於系統的分析和設計,指我們在分析和設計的時候,定義好系統的接口,然后再編碼的時候實現這些接口即可。在父類里定義好子類需要實現的功能,而子類只要實現這些功能即可。
4·依賴倒置原則
其核心思想是:依賴於抽象。具體而言就是高層模塊不依賴於底層模塊,二者都同依賴於抽象;抽象不依賴於具體,具體依賴於抽象。
反面例子:
缺點:耦合太緊密,Light發生變化將影響ToggleSwitch。
解決方法:
優點:更為通用、更為穩定。
優點:
使用傳統過程化程序設計所創建的依賴關系,策略依賴於細節,這是糟糕的,因為策略受到細節改變的影響。依賴倒置原則使細節和策略都依賴於抽象,抽象的穩定性決定了系統的穩定性。
5·接口隔離原則
其核心思想是:使用多個小的專門的接口,而不要使用一個大的總接口。
“不應該強迫客戶依賴於它們不用的方法。接口屬於客戶,不屬於它所在的類層次結構。”