【Spring】(6)靜態代理

一、代理設計模式

根據模式是用來完成什麼工作來劃分,這種方式可分爲創建型模式、結構型模式和行爲型模式 3 種。

代理設計模式屬於三種的的:結構型模式(用於描述如何將類或對象按某種佈局組成更大的結構)。

1.代理模式的定義

爲其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

2.組成

  • 抽象角色:通過接口或抽象類聲明真實角色實現的業務方法。(一般是用接口或抽象類來解決)

  • 代理角色:實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作。(代理真實角色,代理角色一般會做一些其他的操作)

  • 真實角色:實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色調用。 (被代理的角色)

3.優點

  • 職責清晰:
    真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件完成事務,附帶的結果就是編程簡潔清晰。(可以讓真實對象職責更明確!不去關注一些公共的業務)

  • 代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了中介的作用和保護了目標對象的作用。(公共的業務交給了代理角色,實現了業務的分工)

  • 高擴展性。(公共業務發生擴展時(加需求),方便集中管理)

二、租房案例

對象:房東(Renter )、中介(Proxy)

出租事件:Rent接口的rent()方法,用於出租。

關係:中介(代理對象)可以代理房東(真實對象)租房子。

在這裏插入圖片描述

1.抽象角色

抽象角色:代理角色(代理人)和真實角色可以實現)

這裏抽象角色爲一個接口:出租方法,用於出租房屋。

/** 房東Host和代理人中介Proxy都可以實現出租Rent這件事情(方法) */
public interface Rent {
    /** 出租房屋 */
    void rent();
}

2.真實角色

真實角色:真實的角色,可以實現業務方法.

真實角色房東,可以實現出租房屋。房東僅僅只用關注出租房屋。

/** 房東:可以出租房屋的人 */
public class Renter implements Rent {
    @Override
    public void rent() {
        System.out.println("房東出租房子。");
    }
}

3.代理角色

代理角色:是真實對象的代理,也可以實現業務方法。

代理角色中介,不僅可以實現代理角色出租房屋,他還可以在租房前做一些別的事情。比如看房,籤合同

/** 代理人中介 */
public class Proxy implements Rent {
    private Renter host;
    public Proxy(Renter host) {
        this.host = host;
    }

    @Override
    public void rent() {
        before();
        host.rent();
        after();
    }

    private void before() {
        System.out.println("----- 中介帶你看房 -----");
    }
    private void after() {
        System.out.println("----- 中介帶你籤合同 -----");
    }

}

4.測試

有一個租客需要租房子,租客找中介租到了房子。

中介代理了房東,幫房東出租了房子,還幫房東做一些別的事情,比如看房,籤合同。職責明確。

同時,代理還保護了真實的房東信息(對目標對象進行保護)。

/** 租客:需要租房子的人 */
public class Tenant {
    /** 顧客去租房 */
    public static void main(String[] args) {
        // 找到中介(中介代理了某個房東)
        Proxy proxy = new Proxy(new Renter());
        // 找中介租房子
        proxy.rent();
    }
}

輸出:

可以看到中介(代理對象)幫房東(真實對象)出租了房子,同時還幫房東解決了一些其他的問題。

----- 中介帶你看房 -----
房東出租房子。
----- 中介帶你籤合同 -----

三、真實業務案例

需求:

增加業務日誌輸出功能:業務調用前需要輸出調用的方法名,調用後需要輸出返回值。

1.抽象角色

抽象角色:用戶增刪改查操作接口。

/** 用戶數據訪問層接口 */
public interface UserDao {
    void ins();
    void del();
    void upd();
    void sel();
}

2.真實角色

真實對象:用戶增刪改查操作接口的實現類。

public class UserDaoImpl implements UserDao {
    @Override
    public void ins() {
        System.out.println("insert命令");
    }

    @Override
    public void del() {
        System.out.println("delete命令");
    }

    @Override
    public void upd() {
        System.out.println("update命令");
    }

    @Override
    public void sel() {
        System.out.println("select命令");
    }
}

3.代理角色

代理對象:用於代理真實角色,讓真實角色職責更清晰明確。

/** 增加業務日誌打印:調用前需要輸出調用的方法名,調用後需要輸出返回值 */
public class UserDaoImplProxy implements UserDao {
    private UserDao userDao;

    public void setUserDaoImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void ins() {
        log("----- 執行了ins()方法 -----");
        userDao.ins();
        log("----- 無返回值 -----");
    }

    @Override
    public void del() {
        log("----- 執行了del()方法 -----");
        userDao.del();
        log("----- 無返回值 -----");
    }

    @Override
    public void upd() {
        log("----- 執行了upd()方法 -----");
        userDao.upd();
        log("----- 無返回值 -----");
    }

    @Override
    public void sel() {
        log("----- 執行了sel()方法 -----");
        userDao.sel();
        log("----- 無返回值 -----");
    }

    /** 日誌 */
    private void log(String name) {
        System.out.println("[info]: "+name);
    }
}

4.測試

創建代理對象,放入需要代理的真實對象,調用業務方法。

public class Test {
    public static void main(String[] args) {
        // 代理對象,新增日誌打印
        UserDaoImplProxy userDaoProxy = new UserDaoImplProxy();
        // 代理原本對象UserDaoImpl
        userDaoProxy.setUserDaoImpl(new UserDaoImpl());
        // 執行方法
        userDaoProxy.ins();
        userDaoProxy.del();
        userDaoProxy.upd();
        userDaoProxy.sel();
    }
}

輸出:

可以看到真實對象UserDaoImpl被代理對象UserDaoImplProxy給代理了,並且實現了新增的業務。

[info]: ----- 執行了ins()方法 -----
insert命令
[info]: ----- 無返回值 -----
[info]: ----- 執行了del()方法 -----
delete命令
[info]: ----- 無返回值 -----
[info]: ----- 執行了upd()方法 -----
update命令
[info]: ----- 無返回值 -----
[info]: ----- 執行了sel()方法 -----
select命令
[info]: ----- 無返回值 -----

四、備註

通過上面,我們大概瞭解了靜態代理,但是靜態代理有個缺點。

靜態代理缺點 :每一個真實對象會產生一個代理角色,代碼量會翻倍,開發效率變低(靜態代理是在編譯期就已經確定代理類和真實類的關係,並且生成代理類的)。

但是有方法解決的!使用 動態代理 (動態代理是在運行期利用JVM的 反射 機制生成代理類,這裏是直接生成類的字節碼,然後通過類加載器載入JAVA虛擬機執行)!

相關

我的該分類的其他相關文章,請點擊:【Spring + Spring MVC + MyBatis】文章目錄

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