java方法增強的三種方式:繼承,裝飾和代理

在java中梦抢,在不改變源代碼的情況下般贼,實現(xiàn)方法增強的方式有三種:

  • 1,繼承
  • 2奥吩,裝飾者模式
  • 3哼蛆,代理模式(靜態(tài)代理和動態(tài)代理)
1,繼承模式:
  • 簡單來說霞赫,就是通過繼承的方式腮介,在子類方法中添加相應(yīng)的增強方法,然后通過調(diào)用子類方法來實現(xiàn)增強绩脆。
//繼承比較簡單萤厅,直接繼承,重寫中調(diào)用父類方法即可
2靴迫,裝飾者模式:
  • 裝飾者模式是真正完全不改變源碼的情況下增強方法的一種方式惕味,即便是調(diào)用方式也無需改變
  • 這里用自定義的連接池來進(jìn)行說明
  • 在自定義連接池中,如果沒有增強過Connection的話玉锌,那么是不能按照原來的方式直接調(diào)用connection.close();方法的名挥,那么可以通過裝飾,把連接池中的Connection對象直接在放入池之前包裝成我自定義的Connection主守,這樣從連接池中取出來的連接也是我自定義的連接禀倔,那么只需要在自定義的方法中實現(xiàn)close()和prepareStatement等就可以達(dá)到直接調(diào)用關(guān)閉方法的目的榄融,具體如下:
//1,自定義連接池
/*
 * 對JDBC連接的封裝救湖,也就是自定義連接池
 * 其他一些方法也需要重寫愧杯,但是不需要任何改變,所以這里就沒有貼出來
 */
public class JDBCDatasource implements DataSource {
    private static LinkedList<Connection> connections = new LinkedList<Connection>();
    //往連接池中添加連接
    static{
        for(int i=0;i<5;i++){
            Connection connection = JDBCUtil.getConnection();
            JDBCConnection theConnection = new JDBCConnection(connections, connection);
            connections.add(theConnection);
        }
    }
    //重寫這一個方法鞋既,如果沒有增強過connection的話力九,需要調(diào)用這個方法歸還連接到連接池中
    @Override
    public Connection getConnection() throws SQLException {
        if (connections.size() == 0) {
            for(int i=0;i<5;i++){
                Connection connection = JDBCUtil.getConnection();
                JDBCConnection theConnection = new JDBCConnection(connections, connection);
                connections.add(theConnection);
            }
        }
        return connections.removeFirst();
    }
     //新增一個方法
    public void returnConnection(Connection connection){
        connections.add(connection);
    }
}

//2,自定義連接類邑闺,實現(xiàn)相應(yīng)的方法跌前,并在自定義的連接池中進(jìn)行包裝,具體看1中的代碼
//其他一些不需要修改的覆蓋方法這里不再貼出
public class JDBCConnection implements Connection {
    private Connection connection;
    private LinkedList<Connection> connections;
    public JDBCConnection(List<Connection> connections, Connection connection) {
        this.connections = (LinkedList<Connection>) connections;
        this.connection = connection;
    }
    //如果想要在關(guān)閉的時候添加到連接池陡舅,那么需要把連接池傳進(jìn)來抵乓,傳進(jìn)來最好的時候就是創(chuàng)建的時候
    @Override
    public void close() throws SQLException {
        System.out.println("here here!");
        connections.add(connection);
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }
}

//測試
JDBCDatasource datasource = new JDBCDatasource();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
    connection = datasource.getConnection();
    preparedStatement = connection.prepareStatement("select * from product;");
    resultSet = preparedStatement.executeQuery();
    while(resultSet.next()){
        System.out.println(resultSet.getString("pname"));
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    //這行代碼中封裝了connection.close()方法
    JDBCUtil.closeAll(connection, preparedStatement, resultSet);
}

3,代理模式:
  • 代理分為動態(tài)代理和靜態(tài)代理靶衍,區(qū)別就是靜態(tài)代理是自己創(chuàng)建一個代理類灾炭,實現(xiàn)相應(yīng)的被代理對象的方法,增加相應(yīng)的增強代碼摊灭。而動態(tài)代理是通過類加載器咆贬,反射等在運行時創(chuàng)建代理類,也就是不需要手動創(chuàng)建代理類帚呼,在對應(yīng)的代理方法newProxyInstance中的代碼塊中直接添加增強代碼掏缎;
  • 動態(tài)代理是在靜態(tài)代理的基礎(chǔ)上的拓展,所以先看下靜態(tài)代理:
//1,首先需要有一個接口類煤杀,方便目標(biāo)對象和代理對象去實現(xiàn)
public interface DogInterface {
    public void eat();
    public void run();
}

//2眷蜈,目標(biāo)對象中實現(xiàn)借口類
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,創(chuàng)建一個代理對象,在代理對象中實現(xiàn)借口類沈自,并在對應(yīng)的方法中調(diào)用目標(biāo)對象的方法酌儒。
public class DogProxy implements DogInterface {
    @Override
    public void eat() {
        System.out.println("dog在eat前,準(zhǔn)備工作代碼等");
                //這里調(diào)用目標(biāo)對象的方法
        Dog dog = new Dog();
        dog.eat();
        System.out.println("dog在eat后收尾工作代碼等");
    }
    @Override
    public void run() {
    }
}

//4,實際使用時候使用代理對象即可
public void proxyTest(){
    DogProxy proxy = new DogProxy();
    proxy.eat();//這里就ok了
}
  • 下面是動態(tài)代理的代碼實現(xiàn)枯途,前兩步是完全一致的
    有一點需要注意的是:動態(tài)代理方法雖然能增強方法忌怎,但主要的使用場合是在攔截中進(jìn)行相應(yīng)的處理,如在全局的攔截器中進(jìn)行亂碼處理等
//1,首先需要有一個接口類酪夷,方便目標(biāo)對象和代理對象去實現(xiàn)
public interface DogInterface {
    public void eat();
    public void run();
}

//2榴啸,目標(biāo)對象中實現(xiàn)借口類
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,在調(diào)用的時候使用代理類調(diào)用靜態(tài)方法創(chuàng)建動態(tài)代理
 public void dynamicProxyTest(){
    DogInterface proxy = (DogInterface) Proxy.newProxyInstance(
            Dog.class.getClassLoader(), 
            Dog.class.getInterfaces(), //new Class[]{DogInterface.class}
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("before");
                    method.invoke(new Dog(), args);
                    System.out.println("after");
                return null;
        }
    });
    proxy.eat();
    proxy.run();
}
//搞定晚岭!
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸥印,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌库说,老刑警劉巖狂鞋,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異潜的,居然都是意外死亡骚揍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門啰挪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疏咐,“玉大人,你說我怎么就攤上這事脐供。” “怎么了借跪?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵政己,是天一觀的道長。 經(jīng)常有香客問我掏愁,道長歇由,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任果港,我火速辦了婚禮沦泌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘辛掠。我一直安慰自己谢谦,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布萝衩。 她就那樣靜靜地躺著回挽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猩谊。 梳的紋絲不亂的頭發(fā)上千劈,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音牌捷,去河邊找鬼墙牌。 笑死,一個胖子當(dāng)著我的面吹牛暗甥,可吹牛的內(nèi)容都是我干的喜滨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼淋袖,長吁一口氣:“原來是場噩夢啊……” “哼鸿市!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤焰情,失蹤者是張志新(化名)和其女友劉穎陌凳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體内舟,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡合敦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了验游。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片充岛。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耕蝉,靈堂內(nèi)的尸體忽然破棺而出崔梗,到底是詐尸還是另有隱情,我是刑警寧澤垒在,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布蒜魄,位于F島的核電站,受9級特大地震影響场躯,放射性物質(zhì)發(fā)生泄漏谈为。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一踢关、第九天 我趴在偏房一處隱蔽的房頂上張望伞鲫。 院中可真熱鬧,春花似錦签舞、人聲如沸秕脓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撒会。三九已至,卻和暖如春师妙,著一層夾襖步出監(jiān)牢的瞬間诵肛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工默穴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怔檩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓蓄诽,卻偏偏與公主長得像薛训,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仑氛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法乙埃,類相關(guān)的語法闸英,內(nèi)部類的語法,繼承相關(guān)的語法介袜,異常的語法甫何,線程的語...
    子非魚_t_閱讀 31,639評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)遇伞,斷路器辙喂,智...
    卡卡羅2017閱讀 134,662評論 18 139
  • 轉(zhuǎn)自:http://blog.csdn.net/jackfrued/article/details/4492194...
    王帥199207閱讀 8,529評論 3 93
  • 文章作者:Tyan博客:noahsnail.com Chapter 2 Creating and Destroyi...
    SnailTyan閱讀 644評論 0 1
  • 不如意事常八九巍耗,可與語人無二三。 淡漠的性格渐排,不是生下來就有的炬太,更多的是因為人情淡薄所致。每次總是付出百分百...
    蟬茶閱讀 330評論 0 1