有時目標物件不可直接存取,只能通過代理物件存取
圖示:
面向介面程式設計
靜態代理物件程式碼
package com.example.service.impl;
import com.example.service.Service;
public class Agent implements Service {
//定義介面物件
public Service target;
public Agent(){}
//傳入介面物件
public Agent(Service target){
this.target = target;
}
@Override
public void sing() {
System.out.println("協商演出時間......");
System.out.println("協商演出地點......");
//目標物件完成核心業務,介面指向實現類,呼叫實現類的方法
target.sing();
System.out.println("協商演出費用......");
}
}
位於:java.lang.reflect.Proxy包下
有一個核心方法:Proxy.newProxyInstance(....),專門獲取動態代理物件,有三個引數
引數1:ClassLoader loader
引數2:Class<?>[] interfaces
上面兩個引數為代理物件動態的建立和呼叫目標物件的方法提供了資料支援,第3個引數相當於呼叫程式
引數3:InvocationHandler
new InvocationHandler() {
@Override
public Object invoke(
Object obj,
//用來反射呼叫方法
Method method,
//待呼叫方法需要的引數
Object[] args)
throws Throwable {
//擴充套件業務
System.out.println("協商演出時間......");
System.out.println("協商演出地點......");
//核心業務,具體呼叫什麼方法根據外層業務來反射呼叫對應方法
Object res = method.invoke(target, args);
//擴充套件業務
System.out.println("協商演出費用......");
//目標物件執行的目標方法的返回值
return res;
}
}
代理工廠程式碼
package com.example.proxy;
import com.example.service.Service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
//目標物件
Service target;
public ProxyFactory(){}
public ProxyFactory(Service target){
this.target = target;
}
//返回代理物件
public Object getAgent(){
return Proxy.newProxyInstance(
//需要知道受代理物件的類資訊
target.getClass().getClassLoader(),
//需要知道受代理物件實現的所有介面資訊
target.getClass().getInterfaces(),
//反射呼叫目標物件的目標方法
new InvocationHandler() {
@Override
public Object invoke(
Object obj,
//用來反射呼叫方法
Method method,
//待呼叫方法需要的引數
Object[] args)
throws Throwable {
//擴充套件業務
System.out.println("協商演出時間......");
System.out.println("協商演出地點......");
//核心業務,具體呼叫什麼方法根據外層業務來反射呼叫對應方法
Object res = method.invoke(target, args);
//擴充套件業務
System.out.println("協商演出費用......");
//目標物件執行的目標方法的返回值
return res;
}
}
);
}
}
測試程式碼範例
package com.example.proxy;
import com.example.service.Service;
import com.example.service.impl.SuperStarZhou;
import org.junit.Test;
public class TestProxyFactory {
@Test
public void testGetProxy(){
//確定客戶需求
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
//根據需求動態返回對應型別的代理物件
Service agent = (Service) factory.getAgent();
//依託對應型別的動態代理物件完成業務:擴充套件業務(動態代理物件完成) + 核心業務(目標物件完成)
agent.sing();
}
@Test
public void testGetProxy2(){
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
Service agent = (Service) factory.getAgent();
String res = (String) agent.show(60);
System.out.println(res);
}
}
可被代理的方法應該是受代理物件實現的所有介面中的方法與其所有實體方法的交集
型別的轉變
@Test
public void testGetProxy2() {
ProxyFactory factory = new ProxyFactory(new SuperStarZhou());
Service agent = (Service) factory.getAgent();
Service liu = new SuperStarLiu();
System.out.println("型別1: " + liu.getClass());
System.out.println("型別2: " + agent.getClass());
}
/*
輸出結果:
型別1: class com.example.service.impl.SuperStarLiu
型別2: class com.sun.proxy.$Proxy7
*/