今天我们来学习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();
}
}
运行结果:
静态代理优缺点:
优点:
- 在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展。
缺点:
- 因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。
- 一旦接口增加方法,目标对象与代理对象都要维护。
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("小万");
}
}
运行结果:
代理模式在实际生活中是非常常见的,就比如内网通过代理穿透防火墙,实现对公网的访问,这就使用到了代理模式。