1. 程式人生 > >dljd_001_通過介面降低程式碼的耦合度(1)

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.以後我們設計到定義變數型別、方法的引數型別及返回值型別一律使用頂層介面方式。