一、代理設計模式
根據模式是用來完成什麼工作來劃分,這種方式可分爲創建型模式、結構型模式和行爲型模式 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】文章目錄