GOF23種設計模式
阿新 • • 發佈:2018-11-16
代理模式(Proxy pattern)
- 核心作用:
通過代理,控制對物件的訪問,可以詳細控制訪問某個(某類)物件的方法,在呼叫這個方法前做前置處理,呼叫這個方法後做後置處理。
AOP(Aspect Oriented Programming面向切面程式設計)的核心實現機制。 - 核心角色:
**抽象角色:**定義代理角色和真實角色的公共對外方法。
**真實角色:**實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫。
關注真正的業務邏輯
**代理角色:**實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並附加自己的操作。
將統一的流程控制放到代理角色中處理。 - 應用場景:
安全代理:遮蔽對真實決角色的直接訪問
遠端代理:通過代理類處理遠端方法呼叫(RMI)
延遲載入:先載入輕量級的代理物件,真正需要再載入真實物件。 - 分類:
4.1靜態代理:
介面類定義Star:
public interface Star {
/**面試*/
void confer();
/**籤合同*/
void signContract();
/**訂機票*/
void bookTicket();
/**唱歌*/
void sing();
/**收沒款*/
void collectMoney();
}
真實物件RealStar:
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("RealStar confer()");
}
@Override
public void signContract() {
System.out.println("RealStar signContract()");
}
public void bookTicket() {
System.out.println("RealStar bookTicket()");
}
@Override
public void sing() {
System.out.println("RealStar(明星) sing()");
}
@Override
public void collectMoney() {
System.out.println("RealStar collectMoney()");
}
}
代理類ProxyStar:
public class ProxyStar implements Star {
RealStar realStar;
public ProxyStar(RealStar realStar) {
super();
this.realStar = realStar;
}
@Override
public void confer() {
System.out.println("ProxyStar confer");
}
@Override
public void signContract() {
System.out.println("ProxyStar signContract");
}
@Override
public void bookTicket() {
System.out.println("ProxyStar bookTicket");
}
@Override
public void sing() {
realStar.sing();//真實的物件去做
}
@Override
public void collectMoney() {
System.out.println("ProxyStar collectMoney");
}
}
測試:
public class Testd {
public static void main(String[] args) {
RealStar realStar=new RealStar();
ProxyStar proxyStar=new ProxyStar(realStar);
proxyStar.confer();
proxyStar.signContract();
proxyStar.sing();
proxyStar.collectMoney();
}
}
結論
4.2動態代理:
相比靜態代理優先:抽象角色中(介面)宣告的所以方法都被轉移待呼叫處理器一個集中的方法處理,這樣,我們可以使用更加靈活和統一的處理眾多的方法。
4.2.1 JDK自帶動態代理
java.lang.reflect.InvocationHandler (處理器介面)
可以通過invoke方法實現對真實角色的代理訪問
每次通過Proxy生成代理類物件時都要指定對應的處理器物件
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
JdkInterface jdk;
public MyInvocationHandler(JdkInterface jdk) {
this.jdk = jdk;
}
//java.lang.reflect.InvocationHandler (處理器介面)
//可以通過invoke方法實現對真實角色的代理訪問
//每次通過Proxy生成代理類物件時都要指定對應的處理器物件
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置處理:目標方法執行之前");//目標方法執行之前處理邏輯與業務
method.invoke(jdk, args);//執行目標方法
System.out.println("後置處理:目標方法執行之後");//目標方法執行之後處理邏輯
return null;
}
}
介面定義:
public interface JdkInterface {
void say(String message);
}
實現類:
public class JDKInterfaceImpl implements JdkInterface {
@Override
public void say(String message) {
System.out.println("輸出語句:"+message);
}
}
測試方法
import java.lang.reflect.Proxy;
public class TestMy {
public static void main(String[] args) {
JdkInterface jdkInterfaceImpl=new JDKInterfaceImpl();
MyInvocationHandler my=new MyInvocationHandler(jdkInterfaceImpl);
JdkInterface projdk= (JdkInterface)Proxy.newProxyInstance(jdkInterfaceImpl.getClass().getClassLoader(), jdkInterfaceImpl.getClass().getInterfaces(), my);
//Proxy.newProxyInstance(loader, interfaces, h);
//ClassLoader loader :指定當前目標物件使用類載入器,寫法固定
//Class<?>[] interfaces:目標物件實現的介面的型別,寫法固定
//InvocationHandler h :事件處理介面,需傳入一個實現類,一般使用匿名內部類
projdk.say("目標方法執行");
}
}
4.2.2 javaassist位元組碼操作庫實現
4.2.3 CGLIB
目標類不能為final,目標物件的方法如果為final/static,那麼就不會被攔截,即不會執行目標物件額外的業務方法。
該類實現了建立子類的方法與代理的方法。getProxy(SuperClass.class)方法通過入參即父類的位元組碼,通過擴充套件父類的class來建立代理物件。intercept()方法攔截所有目標類方法的呼叫,obj表示目標類的例項,method為目標類方法的反射物件,args為方法的動態入參,proxy為代理類例項。proxy.invokeSuper(obj, args)通過代理類呼叫父類中的方法。
定義目標類:
public class Chinese {
/**目標方法未實現任何的介面*/
public void sing() {
System.out.println("吃麵條");
}
}
定義CGLIB代理類工場
public class ProxyFactory implements MethodInterceptor {
//給目標物件建立一個代理物件
public Object getProxyInstance(Class target) {
//1.工具類
Enhancer enhancer=new Enhancer();
//2.設定父類
enhancer.setSuperclass(target);
//3.設定回撥函式
enhancer.setCallback(this);
//4.通過位元組碼技術動態建立子類例項(代理物件)
return enhancer.create();
}
//實現MethodInterceptor介面方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("執行目標方法之前:拿起筷子");
Object object = proxy.invokeSuper(obj, args);//呼叫父類中的方法,執行目標方法
System.out.println("執行目標方法之後:放下筷子");
return object;
}
}
測試方法:
public class CGLIBMain {
public static void main(String[] args) {
ProxyFactory proxyFactory= new ProxyFactory();
//通過生成子類的方式建立代理類
Chinese proxyInstance = (Chinese)proxyFactory.getProxyInstance(Chinese.class);
proxyInstance.sing();
System.out.println();
System.out.println(proxyInstance);
}
}
執行結果:
第二種引數寫法
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
super();
this.target = target;
}
//給目標物件建立一個代理物件
public Object getProxyInstance() {
//1.工具類
Enhancer enhancer=new Enhancer();
//2.設定父類
enhancer.setSuperclass(target.getClass());
//3.設定回撥函式
enhancer.setCallback(this);
//4.通過位元組碼技術動態建立子類例項(代理物件)
return enhancer.create();
}
//實現MethodInterceptor介面方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("執行目標方法之前:拿起筷子");
Object object = method.invoke(target, args);//呼叫父類中的方法,執行目標方法
System.out.println("執行目標方法之後:放下筷子");
return object;
}
}
測試方法:
public class CGLIBMain {
public static void main(String[] args) {
Chinese chinese=new Chinese();
ProxyFactory proxyFactory= new ProxyFactory(chinese);
//通過生成子類的方式建立代理類
Chinese proxyInstance = (Chinese)proxyFactory.getProxyInstance();
proxyInstance.sing();
System.out.println();
System.out.println(proxyInstance);
}
}
測試結果
4.2.4 ASM(底層使用指令,可維護性較差)