代理模式

来源:互联网 发布:苹果7为什么4g网络很慢 编辑:程序博客网 时间:2024/06/05 18:55

代理设计模式(Proxy Pattern),为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式中涉及的角色:

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

宏观而言,代理模式分为两种类型,动态代理和静态代理。
静态代理:代理和被代理对象在代理之前是确定的,他们都实现相同的接口或继承了相同的抽象类。
这里以计算动物的奔跑时间为例,
继承的方式实现静态代理:

/** * @author BeautifulSoup * 定义全局接口,用于奔跑 */public interface Run {    void run();}/** * @author BeautifulSoup * 定义真实对象完成真实操作. */public class Animal implements Run {    public void run() {        System.out.println("动物在奔跑");        try {            Thread.sleep(new Random().nextInt(1000));//模拟动物奔跑        } catch (InterruptedException e) {            e.printStackTrace();        }    }}/** * @author BeautifulSoup * 得到代理对象,为满足实际需求而进行某方面的增强 */public class AnimalProxy extends Animal {    @Override    public void run() {        long startTime=System.currentTimeMillis();        super.run();        long endTime=System.currentTimeMillis();        System.out.println("动物奔跑的时间为:"+(endTime-startTime));    }}/** * @author BeautifulSoup * 实际开发只需要调用代理对象就能完成指定的操作 */public class TestProxy {    public static void main(String[] args) {        AnimalProxy proxy=new AnimalProxy();        proxy.run();    }}

基于聚合的方式实现代理(该方式更加适合存在多种含有执行顺序的操作的代理中):

//接口和真实对象的代码不变/** * @author BeautifulSoup * 得到代理对象,为满足实际需求而进行某方面的增强 */public class AnimalProxy implements Run {    private Run run;    public AnimalProxy(Run run) {        super();        this.run = run;    }    public void run() {        long startTime=System.currentTimeMillis();        run.run();        long endTime=System.currentTimeMillis();        System.out.println("动物奔跑花费的时间为:"+(endTime-startTime));    }}/** * @author BeautifulSoup * 实际开发只需要调用代理对象就能完成指定的操作 */public class TestProxy {    public static void main(String[] args) {        Animal animal=new Animal();        AnimalProxy proxy=new AnimalProxy(animal);        proxy.run();    }}

动态代理: Java中目前实现动态代理的方式有2中,分别是Jdk的动态代理和CGLib的动态代理,Jdk的动态代理是基于接口的动态代理,也就是说代理类和被代理类对象都应该实现相同的接口;而基于CGLib的动态代理是以类及策划你给的方式来实现的。基于CGLib的动态代理在Spring等框架中应用的比较多。这里仅介绍基于JDK的动态代理,在以后介绍Spring的AOP中会介绍基于类级别的代理方式。

这里还是以记录日志的例子来说明JDK的动态代理的使用。

在实际的开发中,往往都是面向接口编程的,对于持久层的代码,先新建接口后实现。

/** * @author BeautifulSoup * Dao层的接口 */ public interface UserDao {    public void add();    public void update();}/** * @author BeautifulSoup * Dao层的实现类 */public class UserDaoImpl implements UserDao{    public void add() {        System.out.println("add...");    }    public void update() {        System.out.println("update...");    }}/** * @author BeautifulSoup * 现在要为Dao层记录日志 */ public class UserDaoProxy {    private UserDao userDao;    public UserDaoProxy(UserDao userDao) {        super();        this.userDao=userDao;    }    public UserDao createProxy(){        UserDao proxy=(UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(), new InvocationHandler() {            public Object invoke(Object proxy, Method method, Object[] args)                    throws Throwable {                if("update".equals(method.getName())){                    System.out.println("日志记录开始.......");                    Object result=method.invoke(userDao, args);                    System.out.println("日志记录结束");                    return result;                }                return method.invoke(userDao, args);            }        });        return proxy;    }}

客户端测试的代码:

public class Test01 {    @Test    public void test01(){        UserDao userDao=new UserDaoImpl();        userDao.add();        userDao.update();    }    @Test    public void test02(){        UserDao userDao=new UserDaoImpl();        UserDao proxy=new UserDaoProxy(userDao).createProxy();        proxy.add();        proxy.update();    }}

JDK的动态代理是通过Proxy这个类来实现的,其中newInstance方法前两个参数都是固定的,传递接口和类的Class对象(这里也可以知道原理是反射实现的动态代理),第三个参数是InvocationHandler,一般使用匿名内部类的方式来实现参数的传递。其中的抽象方法中的三个参数分别代表被代理类、要被代理的方法和方法中的参数。

0 0