【設計模式】之裝飾器模式

裝飾器設計模式的概念

在實際生產(chǎn)中,某個類的行為(它所提供的方法)已經(jīng)沒法滿足當前的需要了,但是又需要使用原有的部分功能,因此需要對原有對象進行增強——裝飾器設計模式(Decorator Pattern)也叫包裝器模式就是為解決此問題而誕生的,它是對原有類的一個包裝,屬于結構性設計模式。

裝飾器模式在不改變現(xiàn)有類方法簽名的前提下,對當前的類進行了增強。

更多關于設計模式的資料請參考:JAVA高級架構師技術棧

Tips

我們使用繼承也可以實現(xiàn),但是會導致類型結構的膨脹,難以維護。

裝飾器設計模式的生活場景

我們來看一個現(xiàn)實中的例子,老李頭家大兒子去年談了個朋友,女方要求有車才能領證,所以老李家買了一輛奇瑞eQ1,但是女方嫌車速太慢喜歡開快車的感覺...現(xiàn)在老李家正苦惱中...直到有一天在市里工作的大表哥回來聽說該情況后,大表哥說這個好整啊,搞到車行去改裝一下,把速度提上去就可以了啊。

于是乎,老李家去車行把車進行了改裝,車速上去了,媳婦也領到了,皆大歡喜...

這其實就是一個裝飾器的使用案例,原來的eQ1車已經(jīng)沒法滿足了,所以進行了速度增強,其他功能并沒有改變。

裝飾器設計模式的特征

  • 被增強類、增強類實現(xiàn)同一個接口
  • 增強類持有被增強類的引用
  • 被增強的方法調(diào)用增強類的方法,其他方法保持原有的繼續(xù)使用被增強類的舊方法

裝飾器模式的設計

  • 編寫一個接口Car
  • 被增強類 QeqCar 實現(xiàn) Car接口
  • 增強類 Wrapper 實現(xiàn) Car接口
  • 增強類 Wrapper持有被增強類 QeqCar 的引用
1.png
2.png

裝飾器設計模式的實現(xiàn)

  • Car.java
public interface Car {
    void run();

    void stop();
}

  • QeqCar.java
public class QeqCar implements Car {
    @Override
    public void run() {
        System.out.println("Qeq go...");
    }

    @Override
    public void stop() {
        System.out.println("Qeq stop!");
    }
}
  • WrapperCar.java
public class WrapperCar implements Car {

    private Car car;

    public WrapperCar(Car car) {
        this.car = car;
    }

    @Override
    public void run() {
        System.out.println("wapper run...");
    }

    @Override
    public void stop() {
        car.stop();
    }
}
  • WrapperTest .java
public class WrapperTest {

    @Test
    public void 裝飾器模式測試(){
        Car car = new WrapperCar(new QeqCar());
        car.run();
        car.stop();
    }

}

測試輸出:

wapper run...

Qeq stop!

IT人員使用裝飾器模式的編碼場景

IO框架

FilterInputStream.png

在InputStream類的子類中各自引用了其他的子類的引用,如:

BufferedInputStream bis = new BufferedInputStream(InputStream in);

在創(chuàng)建一個BufferedInputStream的時候,就可以傳入一個FileInputStream來作為構造參數(shù),這就是裝飾器模式的使用。

自定義數(shù)據(jù)連接池

自定義數(shù)據(jù)庫連接池的時候我們可能會編寫一個 MyConnection 類實現(xiàn) java.sql.Connection類。
以此來增強原有的mysql驅(qū)動的Connection的實現(xiàn)的close方法,原來是將數(shù)據(jù)庫連接直接關閉,現(xiàn)在可以利用自定義的MyConnection的close方法僅僅將數(shù)據(jù)庫連接扔回數(shù)據(jù)庫連接池,而不再是關閉連接,節(jié)省了網(wǎng)絡IO連接。

自定義的連接類:

public class MyConnection implements Connection {

    // 被增強的引用 (QQ)
    private Connection connection;
    private LinkedList<Connection> pool;

    public MyConnection(Connection connection, LinkedList<Connection> pool) {
        this.connection = connection;
        this.pool = pool;
    }

    @Override
    public void close() throws SQLException {
        // 如何改寫我們的原有邏輯
        // connection.close();
        pool.addLast(connection);
    }
    //...
}

數(shù)據(jù)庫連接池:

public class MyDataSourceFinal implements DataSource {
    // 數(shù)據(jù)庫連接池
    private static LinkedList<Connection> pool = new LinkedList<>();

    static {
        // 創(chuàng)建一些連接對象---池化
        //int initSize = Integer.valueOf(properties.getProperty("initSize"));
        for (int i = 1; i <=  5; i++){

            pool.add(JdbcUtil.getConnection());
        }
    }

    /**
    * 對外暴露的是MyConnection
    * @return 
    * @throws SQLException
    */
    @Override
    public MyConnection getConnection() throws SQLException {
        Connection connection = pool.removeFirst();
        return new MyConnection(connection, pool);
    }


    public static void returnConnection(Connection connection){
        pool.addLast(connection);
    }


    public static int sie(){
        return pool.size();
    }
    // ...
}

單元測試:

public class MyDataSourceFinalTest {
    @Test
    public void test() throws SQLException {


        // 獲取鏈接
        DataSource dataSource = new MyDataSourceFinal();
        Connection connection = dataSource.getConnection();


        String sql = "select * from user where id = ?";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.setInt(1, 1);


        ResultSet resultSet = preparedStatement.executeQuery();

        while(resultSet.next()){
            System.out.println(resultSet.getString("nickname"));
        }

        // 關閉資源
        JdbcUtil.closeAll(resultSet, preparedStatement, null);

        // 使用的是MyConnection的close方法,其實是將連接屬性丟回到了數(shù)據(jù)庫連接池
        connection.close();
    }
}

更多關于設計模式的資料請參考:JAVA高級架構師技術棧

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 在不必改變原類文件和使用繼承的情況下,動態(tài)地擴展一個對象的功能。它是通過創(chuàng)建一個包裝對象,也就是裝飾來包裹真實的對...
    3d0829501918閱讀 664評論 1 4
  • 一、快餐點餐系統(tǒng) 又提到了那個快餐點餐系統(tǒng)(詳見Python與設計模式之工廠類相關模式),不過今天我們只以其中的一...
    喬治大叔閱讀 1,378評論 0 2
  • 在閻宏博士的《JAVA與模式》的書中,對裝飾器模式的描述如下:裝飾模式又名包裝(Wrapper)模式。裝飾模式以對...
    先生zeng閱讀 1,938評論 0 1
  • 裝飾器模式,顧名思義,拘束將某個類重新裝扮一下,使得它比原來更“漂亮”, 或者在功能上更強大,這就是裝飾器模式所要...
    Java小生閱讀 328評論 0 0
  • 天霽曉光侵,花葉茂野林。 山青四面闊,云碧九溪深。 蔬食躬耕作,清茶自淺斟。 不思歸日晚,常夢稻粱吟。
    瀟湘語文閱讀 2,990評論 31 160

友情鏈接更多精彩內(nèi)容