dljd_001_通過介面降低程式碼的耦合度(1)
在學習jdbc之前我們首先來簡單學習一下什麼是面向介面程式設計?面向介面程式設計是怎麼降低程式之間的耦合度的、使用面向介面程式設計給我們帶來了那些好處?
一、需求
比如說有這樣一個需求、讓我們用java程式來簡單模擬一個人駕駛(啟動和停止)一輛寶馬車的。當大部分人看到這個需求之後就會覺得這是不是也太簡單了、當然這大部分人設計出來的程式碼基本是如下的情況:
1.1絕大部分人會有如下的實現:
1.1.1設計人類
package edu.aeon.driver; /** * [說明]:人類 * @author aeon */ public class Person {/** * 當一個類中以屬性的方式引入其它類時、那麼這種方式被稱為聚合 */ private BMW bmw; public BMW getBmw() { return bmw; } public void setBmw(BMW bmw) { this.bmw = bmw; } /** * 駕駛 */ public void driver(){ bmw.run(); bmw.stop(); } }
1.1.2設計寶馬類
package edu.aeon.driver; /** * [說明]:寶馬類 * @author aeon * */ public class BMW { /** * 寶馬的啟動 */ public void run(){ System.out.println("啟動寶馬、行駛..."); } /** * 寶馬的停止 */ public void stop(){ System.out.println("停止寶馬!"); } }
1.1.3測試類:
package edu.aeon.driver; /** * [說明]:人駕駛寶馬測試類 * @author aeon */ public class TestDriver { public static void main(String[] args) { Person person=new Person(); BMW bmw=new BMW(); person.setBmw(bmw); person.driver(); } }
1.1.4測試結果:
我們可以看出來、這個需求是實現了、但是呢這樣設計出來的程式是否合理呢?用合成和聚合(關於合成/聚合的含義詳見本文件總結部分)關係實現人駕駛寶馬是否合理呢?答案是no!
2.1也有大部分會這麼實現
2.1.1設計人類
package edu.aeon.driver; /** * [說明]:人類 * @author aeon */ public class Person { /** * 駕駛 * @param bmw */ public void driver(BMW bmw){ bmw.run(); bmw.stop(); } }
2.1.2設計寶馬類
package edu.aeon.driver; /** * [說明]:寶馬類 * @author aeon * */ public class BMW { /** * 寶馬的啟動 */ public void run(){ System.out.println("啟動寶馬、行駛..."); } /** * 寶馬的停止 */ public void stop(){ System.out.println("停止寶馬!"); } }
2.1.3測試類
package edu.aeon.driver; /** * [說明]:人駕駛寶馬測試類 * @author aeon */ public class TestDriver { public static void main(String[] args) { Person person=new Person(); BMW bmw=new BMW(); person.driver(bmw); } }
2.1.4測試結果
顯然我們看出第二種設計方法比較合理、但是這樣設計出來的程式人類和寶馬類嚴重的耦合在一起。當需求發生變化時(如:駕駛一輛賓士/法拉利/大牛/p1)、我們又要去修改原始碼。那麼怎麼設計出來程式比較完美呢?請看第三種設計(面向介面設計/程式設計)。
3.1極少部分人設計(非常有經驗的人會這麼設計)
3.1.1設計人類
package edu.aeon.driver; /** * [說明]:人類 * @author aeon */ public class Person { /** * 駕駛 * @param car 注意此處:面向介面 */ public void driver(Car car){ //注意 car.run(); car.stop(); } }
3.1.2設計一個汽車介面
package edu.aeon.driver; /** * 汽車介面 * @author aeon */ public interface Car { void run(); void stop(); }
3.1.3設計寶馬類
package edu.aeon.driver; /** * [說明]:寶馬類 * @author aeon * */ public class BMW implements Car{ /** * 寶馬的啟動 */ public void run(){ System.out.println("啟動寶馬、行駛..."); } /** * 寶馬的停止 */ public void stop(){ System.out.println("停止寶馬!"); } }
3.1.4測試類
package edu.aeon.driver; /** * [說明]:人駕駛寶馬測試類 * @author aeon */ public class TestDriver { public static void main(String[] args) { Person person=new Person(); Car car=new BMW(); person.driver(car); } }
3.1.5測試結果截圖:
那麼這種情況可以說設計出來的程式完全符合java力薦的面向介面程式設計、此處也實現了多型、動態繫結、當需求發生變化時(比如我們現在要駕駛一輛法拉利)、只需要寫個法拉利類實現Car這個介面並且重寫其實現方法即可。如:
package edu.aeon.driver; /** * [說明]:法拉利類 * @author aeon * */ public class Ferrari implements Car { /** * 法拉利的啟動 */ @Override public void run() { System.out.println("啟動法拉利、行駛..."); } /** * 法拉利的停止 */ @Override public void stop() { System.out.println("停止法拉利!"); } }
Person類不用我們做任何的修改(解耦)。可見面向介面程式設計給我們帶來的巨大便利。
四、關於合成和聚合:
1.合成和聚合關係有整體和區域性的意義。比如人是一個整體、而這個人的心臟/胃/...是區域性、這裡的心臟/胃/...的人體器官是人的一部分。圖例如下:
人和心就是整體和區域性的關係。人和車是嗎?不是吧!
五、總結
1.合成/聚合有整體和區域性的關係。
2.一個類成為另一個類的方法引數或者返回值、那麼這種關係叫做依賴關係。這裡顯然人依賴於車才能駕駛、如果沒有車那駕駛什麼?但是程式中一定要依賴介面去實現。不然還是耦合在一起。
3.以後我們設計到定義變數型別、方法的引數型別及返回值型別一律使用頂層介面方式。