橋接模式:探索JDBC的接口

原文連接:https://www.cnblogs.com/qiuyong/p/6357839.html

橋接模式:探索JDBC的接口

目錄概要

場景問題

  假設要設計一個電腦商場管理系統的某個模塊設計,電腦分爲品牌和類型兩個緯度,我們應該怎麼解決?我們初學者最容易想到的辦法就是利用繼承的方式,那利用繼承實現的類圖又是什麼樣子呢?我們看圖。

代碼展示

複製代碼

package com.aaron.bridge;

public interface Computer {
    public void sale();
}

class Desktop implements Computer{
    @Override
    public void sale() {
        System.out.println("臺式電腦");
    }
    
}

class Laptop implements Computer{
    @Override
    public void sale() {
        System.out.println("筆記本電腦");
    }
}

class Pad implements Computer{
    @Override
    public void sale() {
        System.out.println("平板電腦");
    }
}

複製代碼

宏碁品牌的三種類型

複製代碼

package com.aaron.bridge;


public class AcerDesktop extends Desktop{
    @Override
    public void sale() {
        System.out.println("宏碁臺式機");
    }
}

class AcerLaptop extends Laptop{
    @Override
    public void sale() {
        System.out.println("宏碁筆記本電腦");
    }
}

class AcerPad extends Pad{
    @Override
    public void sale() {
        System.out.println("宏碁平板電腦");
    }
}

複製代碼

蘋果品牌的三種類型

複製代碼

package com.aaron.bridge;

public class AppleDesktop extends Desktop{
    @Override
    public void sale() {
        System.out.println("蘋果臺式機");
    }
}

class AppleLaptop extends Laptop{
    @Override
    public void sale() {
        System.out.println("蘋果筆記本電腦");
    }
}

class ApplePad extends Pad{
    @Override
    public void sale() {
        System.out.println("蘋果平板電腦");
    }
}

複製代碼

戴爾品牌的三種類型

複製代碼

package com.aaron.bridge;

public class DellDesktop extends Desktop{
    @Override
    public void sale() {
        System.out.println("戴爾臺式機");
    }
}

class DellLaptop extends Laptop{
    @Override
    public void sale() {
        System.out.println("戴爾筆記本電腦");
    }
}

class DellPad extends Pad{
    @Override
    public void sale() {
        System.out.println("戴爾平板電腦");
    }
}

複製代碼

思考:假設我們的系統按照上述思路設計。當我們新增一個品牌的時候,怎麼辦?當然分別要在臺式機、筆記本電腦、平板電腦下又添加三個類就搞定。當我們新增一個機器類型的時候又怎麼辦?當然分別在機器類型又把所有的品牌再添加一次。這樣解決起來感覺也不過如此也不難嘛?但是,假設我們電腦商城,添加10個、100個品牌,又添加10種機型,與此同時這個系統時已經開發完畢,只是在維護的系統,那麼我們怎麼辦?這樣人工代碼會超級痛苦,假設又有很多這樣的問題?那麼我們豈不是變成無腦碼農了?

問題:違背單一職責原則(一個類只由一個維度影響)、開閉原則(對拓展開放,對修改關閉)。

解決方案

1、什麼是橋接模式?

  將兩個維度(抽象、實現)分離,使它們都可以獨立地變化。

2、橋接模式的分析

  類型:臺式機、筆記本電腦、平板電腦。

  品牌:宏碁、蘋果、戴爾。

  將上述問題分爲兩個緯度類型和品牌。我們剛剛也討論了,就是因爲拓展性問題,當添加一個新的類型或者品牌的時候,不會對其他類型或者品牌產生影響。只要解決這個問題,那麼就大功告成。那我們就從橋接模式的類圖開始理解。

Abstraction:

       抽象部分的接口。通常在這個對象裏面,要維護一個實現部分的對象引用,在抽象對象裏面的方法,需要調用實現部分的對象來完成。這個對象裏面的方法,通常都是跟具體的業務相關的方法。

RefinedAbstraction:

       擴展抽象部分的接口,通常在這些對象裏面,定義跟實際業務相關的方法,這些方法的實現通常會使用Abstraction中定義的方法,也可能需要調用實現部分的對象來完成。

Implementor:

       定義實現部分的接口,這個接口不用和Abstraction裏面的方法一致(根據約定優於配置原則,建議跟Abstraction一致。),通常是由Implementor接口提供基本的操作,而Abstraction裏面定義的是基於這些基本操作的業務方法,也就是說Abstraction定義了基於這些基本操作的較高層次的操作。

ConcreteImplementor:

       真正實現Implementor接口的對象。

3、橋接模式代碼實現

 

(1)實現部分接口

複製代碼

package com.aaron.bridge;

/**
 * 
 * @author xiaoyongAaron
 * 品牌緯度-實現部分接口
 */
public interface ImplementorBrand {
    public void sale();
}

class  ConcreteImplementorAcer implements ImplementorBrand{

    @Override
    public void sale() {
        System.out.println("宏碁品牌");
    }
}

class ConcreteImplementorApple implements ImplementorBrand{
    @Override
    public void sale() {
        System.out.println("蘋果品牌");
    }
}

class ConcreteImplementorDell implements ImplementorBrand{
    @Override
    public void sale() {
        System.out.println("戴爾品牌");        
    }
}

複製代碼

 (2)抽象部分

複製代碼

package com.aaron.bridge;

/**
 * 機器類型緯度-抽象部分
 * @author xiaoyongAaron
 */
public class AbstractionComputer {
     protected ImplementorBrand brand;
          
     public AbstractionComputer(ImplementorBrand brand){
         this.brand=brand;
     }
     
     public void sale(){
        brand.sale(); 
     };

}

/**
 * 擴展部分
 * @author xiaoyongAaron
 */
class RefinedAbstractionDesktop extends AbstractionComputer{
    public RefinedAbstractionDesktop(ImplementorBrand brand) {
        super(brand);
    }

    @Override
    public void sale() {
        //添加自己的特性,實際業務。
        paly();
        super.sale();
    }
    
    public void paly(){
        System.out.println("我臺式機抗摔打");
    }
}

class RefinedAbstractionLaptop extends AbstractionComputer{
    public RefinedAbstractionLaptop(ImplementorBrand brand) {
        super(brand);
    }

    @Override
    public void sale() {
        //添加自己的特性,實際業務。
        lighting();
        super.sale();
    }
    
    public void lighting(){
        System.out.println("我筆記本電腦充電5分鐘,續航5小時");
    }
}

class RefinedAbstractionPad extends AbstractionComputer{
    public RefinedAbstractionPad(ImplementorBrand brand) {
        super(brand);
    }

    @Override
    public void sale() {
        //添加自己的特性,實際業務。
        weighting();
        super.sale();
    }
    
    public void weighting(){
        System.out.println("我平板電腦便於攜帶");
    }
}

複製代碼

(3)客戶端調用

複製代碼

package com.aaron.bridge;

public class Clent {
    
    public static void main(String[] args) {
        //品牌緯度-實現部分接口
        ImplementorBrand brand=new ConcreteImplementorApple();
        //機器類型緯度
        AbstractionComputer computer=new RefinedAbstractionLaptop(brand);
        
        computer.sale();
    }
}

複製代碼

(4)運行結果

問題回顧

 1、什麼是橋接模式、爲什麼要橋接?

  簡單說橋接模式就是把兩個緯度分離,所以說當我們在實際開發的時候,遇到兩個維度問題的時候,直接條件反射橋接模式。就像上述問題,當有兩個維度(品牌+機器類型)賦予給一個類的時候,基於單一職責原則,需要把它們解耦。那通過上述範例可知,那麼我們就需要一座橋一樣,把兩個緯度用一箇中間物(類或者接口)把它們關聯起來,從而達到我們的目的。

2、橋接模式怎麼接?

  核心:如何把Implementor對象傳遞到抽象接口。

  (1)如上述描述,利用構造函數傳參。

  (2)創造無參構造函數,添加get、set方法。

  (3)工廠模式:參考設計模式的工廠模式。

  (4)IOC控制反轉,最經典的就是Spring容器。內部的實現原理原本創建對象都是由我們自己管理,但是把這一步驟交給容器管理,就不用我們擔心了。例如在JDBC的設計當中,充當這個角色的就是DriverManage去把對象注入在抽象接口當中。

3、橋接模式本質和經驗

  (1)本質:抽象與實現(兩個緯度)分離。

  (2)多用對象組合(has-A),少用繼承。

  (3)開閉原則:我們應該對代碼拓展開放,拒絕代碼修改。

實際應用場景

參考:https://www.oschina.net/question/1435262_140274

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章