设计模式之代理模式
定义
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 —— [ 百度百科 ]
分类
- 静态代理模式
- 动态代理模式
解释说明
-
静态代理模式
- 代理角色和真实角色实现同一个借口,具备统一的行为。另外,在代理角色中,内置了真实角色,所有对真实角色方法的调用,都可以委托给代理角色,由其在内部实现对真实角色方法的调用,甚至是在其中添加更加复杂的业务逻辑。
代码块
public class Test {
//抽象角色
interface Man{
public void say();
}
//真实角色
class ManImpl implements Man{
@Override
public void say() {
System.out.println("我是真实角色");
}
}
//代理角色
class ManProxy implements Man{
private ManImpl manImpl = new ManImpl();
@Override
public void say() {
System.out.println("这是代理角色新加的业务逻辑");
manImpl.say();
}
}
//测试
public static void main(String[] args) {
//实例化代理角色
ManProxy manProxy = new Test().new ManProxy();
manProxy.say();
}
}
: 以上就是静态代理模式的完整代码。代理角色ManProxy 中内置了真实角色ManImpl 的实例化对象,由于代理角色与真实角色同时实现了Man接口,所以对外提供了一致的服务。当需要调用真实角色的服务的时候,通过代理角色实现对真实角色服务的调用。个人认为,这可以类比于服务的转发,这样可能会更加容易理解。
-
动态代理模式
- 在动态代理模式中,代理模式不在需要实现抽象接口。我们通过java中类的反射机制,实例化真正的角色类型,然后调用真实角色的服务。
代码块
public class Test {
//抽象角色
interface Man{
public void say();
}
//真实角色
class ManImpl implements Man{
@Override
public void say() {
System.out.println("我是真实角色");
}
}
//代理处理器
class ManHandler implements InvocationHandler{
private Man man = new ManImpl();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
object = method.invoke(man, args);//激活调用的方法
return object;
}
}
//测试
public static void main(String[] args) {
ManHandler manHandler = new Test().new ManHandler();
Man manProxy = (Man) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Man.class}, manHandler);
manProxy.say();
}
}
: 以上就是动态代理模式的完整代码示例。在上述代码中,当客户端请求真实对象的服务的时候,我们先通过java自带的代理模式,将我们创建的代理对象manProxy与代理处理器ManHandler 关联到一起。当我们通过代理对象manProxy发起say方法的访问的时候,会去执行ManHandler 中的invoke方法,通过方法参数名以及我们内置的真实对象实例,java帮我们动态的映射到真实对象的方法上去,从而完成了动态代理。
总结
优点
- 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。 - 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
- 高扩展性
缺点
- 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。
- 实现代理模式需要额外的工作,而且有些代理模式的实现过程较为复杂,例如远程代理。。
试用场景
本人亲身经历的使用场景就是java远程方法调用。在本地方法中,通对前台传过来的类名,参数名等等信息,完成对远程服务代理对象的映射,然后再本地调用远程方法,实现配置文件的修改。