創建式模式:抽象工廠/建造者/工廠方法/原型/單例
構造型模式:適配器/橋接/組合/裝飾/外觀/享元/代理
行爲型模式:責任鏈/命令/解釋器/迭代子/中介者/備忘錄/觀察者/狀態/策略/模板方法/訪問者
.......
.......
代理模式:使用一個新的代理類爲目標類(被代理類)進訪問的控制,與裝飾者模式不同,代理類對象可以有多個目標類,控制的目的是爲了在調用目標類方法之前或之後執行某些其他操作、或者增強或減弱目標類的某些方法中的功能,作爲一個委託者起到不改變目標類的核心代碼就能夠實現功能的增強或新功能的添加的作用。
靜態代理:當被代理類(目標類)與代理類(委託類)在程序運行之前已經存在,即運行前就確定了關係生成了字節碼文件,這種由委託類和目標類形成的代理關係就是靜態代理。
代理實例:(經紀人代理明星)【前提是經紀人和明星實現了相同接口】
接口:
/**
* 接口(目標類和委託類必須實現同一個接口)
*/
public interface Star {
public void action();
}
委託類:
/**
* 經紀人類(作爲委託類),要和目標類實現相同的接口
* 可以代理多個實現了相同接口的目標對象(通過構造函數傳入實例對象的引用,面向接口編程、多態)
*/
public class Agent implements Star{
private Star Star;
public Agent(Star star) {
Star = star;
}
private void actionBefore(){
System.out.println("委託者(當前是經紀人)在演出之前執行前置工作");
}
@Override
public void action() {
//在目標類代碼執行之前,添加其他的功能或處理部分邏輯
//代理明星的演出前對第三方邀請商的簽約工作
actionBefore();
//執行目標類的核心工作,真正的執行者
Star.action();
//代理明星的演出後對片酬的分發動作等等
actionAfter();
}
private void actionAfter(){
System.out.println("委託者(當前是經紀人)在演出後執行後置工作");
}
}
目標類:
public class Songer implements Star{
@Override
public void action() {
System.out.println("歌手唱歌");
}
}
public class Actor implements Star{
@Override
public void action() {
System.out.println("演員表演");
}
}
測試當前實例的測試類:
public class StaticProxyTest {
@Test
public void test(){
//創建一個歌手讓經紀人代理,在歌手之前或之後進行功能的加強或處理
Songer songer = new Songer();
new Agent(songer).action();
//創建一個演員讓經紀人代理,在演員出演之前或之後進行功能的加強或處理
Actor actor = new Actor();
new Agent(actor).action();
}
}
1.代理對象服務於實現了相同接口的對象,如果要代理的方法很多,勢必要爲每一種方法都進行代理,靜態代理在程序規模稍大時就無法勝任了。
2.如果接口增加一個方法,除了所有委託類需要實現這個方法外,所有代理類也需要實現此方法。增加了代碼維護的複雜度。
動態代理:(基於JDK的動態代理\Proxy方式)
動態代理它可以直接給某一個目標對象(委託對象)生成一個代理對象,而不需要代理類存在。動態代理與靜態代理模式原理是一樣的,只是動態代理類的源碼是在程序運行期間由JVM根據反射等機制動態的生成,所以不存在代理類的字節碼文件。代理類和委託類的關係是在程序運行時確定。
代理實例:(也用經紀人代理明星這個例子)【前提是經紀人和明星實現了相同接口】
接口:
/**
* 接口(目標類和委託類必須實現同一個接口)
*/
public interface Star {
public void action();
}
目標類:
public class Songer implements Star{
@Override
public void action() {
System.out.println("歌手唱歌");
}
}
委託類由JVM通過反射動態生成
{
調用處理者類:
/**
* 調用處理者(這裏統一處理目標類方法的調用邏輯)
*/
public class InvocationHandlerImp implements InvocationHandler{
private Star star;
public InvocationHandlerImp(Star star) {
this.star = star;
}
/**
*
* @param proxy 當前創建出來的動態代理對象
* @param method 當前調用的方法對象
* @param args 調用的方法參數
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//創建一個歌手讓經紀人代理,在歌手之前或之後進行功能的加強或處理
actionBefore();
//調用當前目標類對象的方法
method.invoke(star);
//代理明星的演出後對片酬的分發動作等等
actionAfter();
return null;
}
private void actionBefore(){
System.out.println("委託者(當前是經紀人)在演出之前執行前置工作");
}
private void actionAfter(){
System.out.println("委託者(當前是經紀人)在演出後執行後置工作");
}
}
結合Proxy類生成代理對象
InvocationHandlerImp invocationHandlerImp = new InvocationHandlerImp(star);
//參數一是一個類加載器
//參數二是目標類上的所有接口的字節碼對象
//參數三是委託者的調用處理者對象
Star starProxy= (Star) Proxy.newProxyInstance(this.getClass().getClassLoader(), Songer.class.getInterfaces(), invocationHandlerImp);
}
測試類代碼:
public class DynamicProxyTest {
@Test
public void test(){
//創建目標類對象
Star star = new Songer();
//創建委託類的調用處理者
InvocationHandlerImp invocationHandlerImp = new InvocationHandlerImp(star);
//參數一是一個類加載器
//參數二是目標類上的所有接口的字節碼對象
//參數三是委託者的調用處理者對象
Star starProxy= (Star) Proxy.newProxyInstance(this.getClass().getClassLoader(), Songer.class.getInterfaces(), invocationHandlerImp);
//調用代理對象的方法(在執行目標類方法之前執行其他業務操作,可以增強了當前目標類的方法,但是實際上核心工作還是目標類完成)
//代理對象每調用一個方法,都會執行一次調用處理者中的invoke方法,可以通過判斷方法名去篩選要處理的方法
starProxy.action();
}
}
動態代理:(基於Cglib的動態代理\Enhancer方式)
如果真實類是一個普通類,沒有實現接口,那麼就採用這種方式, 創建出來真實類的子類作爲代理類,是繼承關係
測試實例:(同上)
/**
* 如果真實類是一個普通類,沒有實現接口,那麼就採用這種方式, 創建出來真實類的子類作爲代理類。
*/
public class DynamicProxyCglibTest {
@Test
public void test(){
//目標類對象
final Songer songer = new Songer();
//創建代理對象
Enhancer enhancer = new Enhancer();
//設置父類
enhancer.setSuperclass(Songer.class);
//設置回調對象
enhancer.setCallback(new MethodInterceptor(){
/**
*
* @param o 代理對象
* @param method 方法對象的引用
* @param objects 方法參數
* @param methodProxy 方法對象的代理
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
actionBefore();
method.invoke(songer);
actionAfter();
return null;
}
});
//創建代理對象調用代理方法
Songer s = (Songer)enhancer.create();
s.action();
}
private void actionBefore(){
System.out.println("委託者(當前是經紀人)在演出之前執行前置工作");
}
private void actionAfter(){
System.out.println("委託者(當前是經紀人)在演出後執行後置工作");
}
}
}