裝飾器設計模式的概念
在實際生產(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 的引用


裝飾器設計模式的實現(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框架

在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高級架構師技術棧