代理模式
今天我們來學習23種設計模式中的第十二種——代理模式。代理模式就是給一個對象提供一個代理,並由代理對象控制對原對象的引用。它使得客戶不能直接與真正的目標對象通信。代理對象是目標對象的代表,其他需要與這個目標對象打交道的操作都是和這個代理對象在交涉。
概念:
代理模式是由於某些原因需要給某對象提供一個代理以控制對該對象的訪問。這時,訪問對象不適合或者不能直接引用目標對象,代理對象將作爲訪問對象和目標對象之間的中介。
特點:
優點:
- 代理模式在客戶端與目標對象之間起到一箇中介作用和保護目標對象的作用;
- 代理對象可以擴展目標對象的功能;
- 代理模式能將客戶端與目標對象分離,在一定程度上降低了系統的耦合度。
缺點:
- 在客戶端和目標對象之間增加一個代理對象,會造成請求處理速度變慢;
- 增加了系統的複雜度。
代碼:
1. 靜態代理
目標接口
package cn.ppdxzz.proxy.staticproxy;
/**
* description:目標接口
* @author: PeiChen JavaAnything
*/
public interface ITeacherDao {
/**
* 教師授課的方法
*/
void teach();
}
目標對象(被代理對象)
package cn.ppdxzz.proxy.staticproxy;
/**
* description:目標對象(被代理對象)
* @author: PeiChen JavaAnything
*/
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("教師授課中...");
}
}
代理對象
package cn.ppdxzz.proxy.staticproxy;
/**
* description:代理對象
* @author: PeiChen JavaAnything
*/
public class TeacherDaoProxy implements ITeacherDao {
/**
* 目標對象,通過接口來聚合
*/
private final ITeacherDao targetObject;
public TeacherDaoProxy(ITeacherDao targetObject) {
this.targetObject = targetObject;
}
/**
* 具體代理操作的實現
*/
@Override
public void teach() {
System.out.println("開始代理某些操作...");
targetObject.teach();
System.out.println("代理操作完成");
}
}
靜態代理客戶端
package cn.ppdxzz.proxy.staticproxy;
/**
* description:靜態代理客戶端
* @author: PeiChen JavaAnything
*/
public class Client {
public static void main(String[] args) {
//1. 創建目標對象(被代理對象)
TeacherDao targetObject = new TeacherDao();
//2. 創建代理對象,把被代理對象傳給代理對象
TeacherDaoProxy proxy = new TeacherDaoProxy(targetObject);
//3. 通過代理對象,去調用被代理對象的方法,執行的是代理對象的方法,代理對象再去調用目標對象的方法
proxy.teach();
}
}
運行結果:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eTEgcLkh-1591153932251)(D:\cloudnote\images\image-20200426101603467.png)]
靜態代理優缺點:
優點:
- 在不修改目標對象的功能前提下,能通過代理對象對目標功能擴展。
缺點:
-
因爲代理對象需要與目標對象實現一樣的接口,所以會有很多代理類。
-
一旦接口增加方法,目標對象與代理對象都要維護。
2. 動態代理
目標接口
package cn.ppdxzz.proxy.dynamicproxy;
/**
* description:目標接口
* @author: PeiChen JavaAnything
*/
public interface ITeacherDao {
/**
* 授課
*/
void teach();
/**
* 問好
* @param name 姓名
*/
void sayHello(String name);
}
目標對象(被代理對象)
package cn.ppdxzz.proxy.dynamicproxy;
/**
* description:目標對象(被代理對象)
* @author: PeiChen JavaAnything
*/
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println("教師授課中...");
}
@Override
public void sayHello(String name) {
System.out.println("hello" + name);
}
}
代理對象
package cn.ppdxzz.proxy.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* description:代理對象
* @author: PeiChen JavaAnything
*/
public class ProxyFactory {
/**
* 維護一個Object類型的目標對象
*/
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理開始...");
//反射機制調用目標對象的方法
Object returnVal = method.invoke(target, args);
System.out.println("JDK代理提交");
return returnVal;
}
});
}
}
動態代理客戶端
package cn.ppdxzz.proxy.dynamicproxy;
/**
* description:動態代理客戶端
* @author: PeiChen JavaAnything
*/
public class Client {
public static void main(String[] args) {
//創建目標對象
ITeacherDao target = new TeacherDao();
//創建代理對象
ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
proxyInstance.teach();
proxyInstance.sayHello("小萬");
}
}
運行結果:
代理模式在實際生活中是非常常見的,就比如內網通過代理穿透防火牆,實現對公網的訪問,這就使用到了代理模式。