設計模式:裝飾器模式實現 固定類功能

一年半前寫了一篇文章Spring3:AOP,是當時學習如何使用Spring AOP的時候寫的,比較基礎。這篇文章最後的推薦以及回覆認爲我寫的對你們有幫助的評論有不少,可是如今從我我的的角度來看,這篇文章寫得並很差,甚至能夠說是沒有太多實質性的內容,所以這些推薦和評論讓我以爲受之有愧。html

基於以上緣由,更新一篇文章,從最基礎的原始代碼–>使用設計模式(裝飾器模式與代理)–>使用AOP三個層次來說解一下爲何咱們要使用AOP,但願這篇文章能夠對網友朋友們有益。java

原始代碼的寫法

既然要經過代碼來演示,那必需要有例子,這裏個人例子爲:設計模式

1
有一個接口Dao有insert、delete、update三個方法,在insert與update被調用的先後,打印調用前的毫秒數與調用後的毫秒數

首先定義一個Dao接口:ide

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author 五月的倉頡http://www.cnblogs.com/xrq730/p/7003082.html
*/
public interface Dao {
 
    public void insert();
   
    public void delete();
   
    public void update();
   
}

而後定義一個實現類DaoImpl:函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @author 五月的倉頡http://www.cnblogs.com/xrq730/p/7003082.html
*/
public class DaoImpl implements Dao {
 
    @Override
    public void insert() {
        System.out.println( "DaoImpl.insert()" );
    }
 
    @Override
    public void delete() {
        System.out.println( "DaoImpl.delete()" );
    }
 
    @Override
    public void update() {
        System.out.println( "DaoImpl.update()" );
    }
   
}

最原始的寫法,我要在調用insert()與update()方法先後分別打印時間,就只能定義一個新的類包一層,在調用insert()方法與update()方法先後分別處理一下,新的類我命名爲ServiceImpl,其實現爲:學習

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @author 五月的倉頡http://www.cnblogs.com/xrq730/p/7003082.html
*/
public class ServiceImpl {
 
    private Dao dao = new DaoImpl();
   
    public void insert() {
        System.out.println( "insert()方法開始時間:" + System.currentTimeMillis());
        dao.insert();
        System.out.println( "insert()方法結束時間:" + System.currentTimeMillis());
    }
   
    public void delete() {
        dao.delete();
    }
   
    public void update() {
        System.out.println( "update()方法開始時間:" + System.currentTimeMillis());
        dao.update();
        System.out.println( "update()方法結束時間:" + System.currentTimeMillis());
    }
   
}

這是最原始的寫法,這種寫法的缺點也是一目瞭然:this

  • 方法調用先後輸出時間的邏輯沒法複用,若是有別的地方要增長這段邏輯就得再寫一遍
  • 若是Dao有其它實現類,那麼必須新增一個類去包裝該實現類,這將致使類數量不斷膨脹

使用裝飾器模式

接着咱們使用上設計模式,先用裝飾器模式,看看能解決多少問題。裝飾器模式的核心就是實現Dao接口並持有Dao接口的引用,我將新增的類命名爲LogDao,其實現爲:spa

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @author 五月的倉頡http://www.cnblogs.com/xrq730/p/7003082.html
*/
public class LogDao implements Dao {
 
    private Dao dao;
   
    public LogDao(Dao dao) {
        this .dao = dao;
    }
 
    @Override
    public void insert() {
        System.out.println( "insert()方法開始時間:" + System.currentTimeMillis());
        dao.insert();
        System.out.println( "insert()方法結束時間:" + System.currentTimeMillis());
    }
 
    @Override
    public void delete() {
        dao.delete();
    }
 
    @Override
    public void update() {
        System.out.println( "update()方法開始時間:" + System.currentTimeMillis());
        dao.update();
        System.out.println( "update()方法結束時間:" + System.currentTimeMillis());
    }
 
}

在使用的時候,可使用」Dao dao = new LogDao(new DaoImpl())」的方式,這種方式的優勢爲:設計

  • 透明,對調用方來講,它只知道Dao,而不知道加上了日誌功能
  • 類不會無限膨脹,若是Dao的其它實現類須要輸出日誌,只須要向LogDao的構造函數中傳入不一樣的Dao實現類便可

不過這種方式一樣有明顯的缺點,缺點爲:代理

  • 輸出日誌的邏輯仍是沒法複用
  • 輸出日誌的邏輯與代碼有耦合,若是我要對delete()方法先後一樣輸出時間,須要修改LogDao

可是,這種作法相比最原始的代碼寫法,已經有了很大的改進。

相關文章
相關標籤/搜索