代理模式
定义:给一个对象提供一个代理对象,由这个代理对象控制对原对象的引用,使代理类在客户端和原对象之间起到一个中介的作用。
优点:使用代理模式能够在不改变原来代码功能的基础上对某一对象进行额外的控制,是面向对象中单一职责的体现。
缺点:对于静态代理来说一个接口只服务于一种类型,如果要代理的方法很多则要为每一个方法定义一个接口。
使用时机:当系统需要对某个对象进行额外的控制时。
下面以系统日志记录为例
(1)最简单直接的做法
public class Test
{
private Logger logger = Loger.getLogger(this.getClass().getName());
public void doLgic(String name){
logger.log(name + "开始业务逻辑处理...");
//业务逻辑处理相关程序
System.out.println("业务逻辑处理相关程序");
logger.log(name + "业务逻辑处理结束...");
}
}
//有其他的类的业务逻辑也需要记录日志:
public class Test1
{
private Logger logger = Loger.getLogger(this.getClass().getName());
public void doLgic(String name){
logger.log(name + "开始业务逻辑处理...");
//业务逻辑处理相关程序
System.out.println("业务逻辑处理相关程序");
logger.log(name + "业务逻辑处理结束...");
}
}
这两个类为了记录日志,在处理业务逻辑的代码中加入了有关日志处理的方法,
这些方法加入的模式很相似,混淆了类的单一职责,有什么办法解决这个问题?
(2)静态代理
//定义一个有业务逻辑的接口类:
public interface Test
{
public void doLogic(String name);
}
//具体的逻辑处理类:
public class TestImpl implements Test
{
public void doLogic(){
System.out.println("业务逻辑处理");
}
}
//日志代理类:
public class TestProxy implements Test
{
private Logger logger = Loger.getLogger(this.getClass().getName());
private Test test;
public TestProxy(Test test){
this.test = test;
}
public void doLogic(String name){
logger.log("开始业务逻辑处理...");
//业务逻辑处理
test.doLogic(name);
logger.log("业务逻辑处理结束...");
}
}
//调用代理类,实现日志输出:
public class Client
{
public static void main(String[] args){
TestProxy testProxy = new TestProxy(new TestImpl());
testProxy.doLogic("小四");
}
}
通过业务逻辑的代理类来调用具体的业务逻辑,同样实现了日志的记录,
而且把日志的记录和业务逻辑进行了分离,这是静态代理。
存在问题就是:每个方法都要有一个代理类,如果系统中的每个类都要日志记录,
那代理类的数量很多。解决办法就是动态代理了。
(3)动态代理
基于JDK的动态代理:
public LogProxy implements InvocationHandler
{
private Logger logger = Loger.getLogger(this.getClass().getName());
private Object delegate;//代理对象
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
Object result = null;
try{
logger.log("开始业务逻辑处理...");
//业务逻辑处理
result = method.invoke(delegate,args);
logger.log("业务逻辑处理结束...");
}catch(Exception e){
logger.log(e.toString());
}
return result;
}
}
public class Client
{
public static void main(String[] args)
{
LogProxy logProxy = new LogProxy();
Test test = (Test)logProxy.bind(new TestImpl());
test.doLogin("小五");
}
}