定义:
为其它的对象提供一种代理以控制这个对象的访问,在某些情况下,一个对象不适合或不能直接引用另外一个对象。而代理对象会在客户端与目标用户之间起到中介的作用
角色:
抽象角色:声明真实对象与代理对象的共同接口
代理角色:代理对象角色内部含有真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便任何时候都能替代真实对象。同时代理对象可以在执行真实对象的操作时,附加其它的操作,相当于对真实对象进行再次的封装
真实角色:代理角色所代表的最终角色,是我们最终要引用的对象
静态代理:
程序运行前已经存在代理类的字节码对象,代理类与委托类在在程序运行前就确认了
代码示例如下:
抽象角色:
public interface UserInfo {
public void queryUser();
public void updateUser();
}
真实角色
public class UserImpl implements UserInfo {
@Override
public void queryUser() {
System.out.println("---查询用户的信息-----");
}
@Override
public void updateUser() {
System.out.println("---更新用户的信息-----");
}
}
代理角色
public class UserProxy implements UserInfo {
private UserInfo userInfo;
public UserProxy(UserInfo userInfo) {
this.userInfo = userInfo;
}
@Override
public void queryUser() {
//可以添加其它的操作
userInfo.queryUser();
}
@Override
public void updateUser() {
//可以添加其它的操作
userInfo.updateUser();
}
}
测试:
public class MyTest {
public static void main(String[] args) {
UserImpl user = new UserImpl();
UserInfo userProxy = new UserProxy(user);
userProxy.updateUser();
userProxy.queryUser();
}
}
运行结果:
动态代理:
动态代理类的的源码是程序在运行期间由jvm根据反射机制动态生成的,所以不存在代理类的字节码文件,代理类与运行类的角色在程序运行时确定
public class UserHandler implements InvocationHandler {
private UserInfo userInfo;
public UserHandler(UserInfo userInfo) {
this.userInfo = userInfo;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
//方法开始前做一些事情
if (method.getName().equals("queryUser")) {
object = method.invoke(userInfo, args);
System.out.println("----end query---");
//可以做其它的事情
}
//方法结束后也可做其它的事情
return object;
}
//测试
public static void main(String[] args) {
UserInfo userInfo = new UserImpl();
UserHandler userHandler = new UserHandler(userInfo);
UserInfo userProxy = (UserInfo)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
new Class[]{UserInfo.class}, userHandler);
userProxy.queryUser();
}
}
测试结果
优点:
业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
缺点:
由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。
实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂,例如远程代理。
适配器模式 代理模式 装饰器模式 总结
只需要将原接口转化为客户希望的另一个接口,就是适配器模式。转化无非就是1.继承原类或者实现原接口 2.持有原接口的对象,再实现目标接口。那么第一种就是类的适配,第二种就是对象的适配。
代理模式和适配器模式最大的区别,代理模式是与原对象实现同一个接口,而适配器类则是匹配新接口,说白了,实现一个新的接口。
在装饰器模式中,必须要有被装饰的类和装饰的类。代理模式一定是自身持有这个对象,不需要从外部传入。而装饰模式的一定是从外部传入,并且可以没有顺序,按照代码的实际需求随意挑换顺序。再从使用上来看,代理模式注重的是隔离限制,让外部不能访问你实际的调用对象,比如权限控制,装饰模式注重的是功能的拓展,在同一个方法下实现更多的功能。