代理模式:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
- 代理模式的主要优点:
- 代理模式在客户端与目标对象之前起到一个中介作用和保护目标对象的作用。
- 代理对象可以扩展目标对象的功能。
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性。
- 其主要缺点是:
- 代理模式会造成系统设计中类的数量增加。
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢。
- 增加了系统的复杂度。
静态代理
静态代理在使用时,需要定义接口或者父类,被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。
应用实例:
- 定义一个接口:ITeacherDao
- 目标对象 TeacherDao 实现接口 ITeacherDao
- 使用静态代理方式,就需要在代理对象 TeacherDaoProxy 中也实现 ITeacherDao
- 调用的时候通过调用代理对象的方法来调用目标对象
- 注意:代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
类图演示:
代码实现:
- 定义接口:
interface ITeacherDao {
void teach();
}
- 目标对象:
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("老师授课中...");
}
}
- 代理对象:
// 代理对象(静态代理)
public class TeacherDaoProxy implements ITeacherDao{
private ITeacherDao target; // 目标对象,通过接口来聚合
// 构造器
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
System.out.println("代理开始...");
target.teach();
System.out.println("代理结束...");
}
}
- 客户端使用:
public class Client {
public static void main(String[] args) {
// 创建目标对象(被代理对象)
TeacherDao teacherDao = new TeacherDao();
// 创建代理对象,同时将被代理对象传给代理对象
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
// 通过代理对象调用到被代理对象的方法
// 执行的是代理对象的方法,代理对象再去调用目标对象的方法
teacherDaoProxy.teach();
}
}
运行结果:
代理开始...
老师授课中...
代理结束...
Process finished with exit code 0
静态代理的优缺点:
- 优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展。
- 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。
- 一旦接口增加方法,目标对象与代理对象都要维护。
动态代理
静态代理其特点是代理类和目标类在代码中是确定的,因此成为静态。静态代理可以在不修改目标对象功能的前提下,对目标功能进行扩展。
- 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理。
- 代理对象的生成,是利用 JDK 的 API,动态的在内存中构建代理对象。
- 动态代理也叫做:JDK代理,接口代理。
- 能在代码运行时动态的改变某个对象的代理,并且能为代理对象动态的增加方法、增加行为。
类图:
public interface ITeacherDao {
void teach(); // 授课方法
}
public class TeacherDao implements ITeacherDao{
@Override
public void teach() {
System.out.println("授课中....");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory {
// 维护一个目标对象,Object
private Object target;
// 构造器,对目标对象进校初始化
public ProxyFactory(Object target) {
this.target = target;
}
// 给目标对象生成一个代理对象
public Object getProxyInstance() {
// 参数说明
// 1. loader
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
* ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法固定
* Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方法确定类型
* InvocationHandler h:事情处理,执行目标对象方法时,
* 会触发事件处理器方法,会把当前执行的目标对象方法作为一个参数传入
*/
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;
}
});
}
}
- 客户端
public class Client {
public static void main(String[] args) {
// 创建一个目标对象
TeacherDao target = new TeacherDao();
// 给目标对象创建代理对象,可以转成 ITeacherDao65
ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance();
// 结果表明:内存中动态生成了代理对象
System.out.println("proxyInstance=" + proxyInstance.getClass());
// 通过代理对象,调用目标对象的方法
proxyInstance.teach();
}
}
运行结果:
proxyInstance=class com.sun.proxy.$Proxy0
JDK代理开始~~~
授课中....
JDK代理提交
Process finished with exit code 0