Proxy代理模式

来源:互联网 发布:淘宝上好的cos店 编辑:程序博客网 时间:2024/05/17 03:28

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

  • 真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。
  • 高扩展性

一个是真正的你要访问的对象(目标类),另一个是代理对象,真正对象与代理
对象实现同一个接口,先访问代理类再访问真正要访问的对象。


代理模式的要求:

  1. 代理这和被代理这实现相同的接口
  2. 代理者必须有被代理这的实例(引用)
  3. 代理这调用被代理这的方法

静态代理:简单代理
代理者和被代理这需要是实现共同的接口,即我们的装饰模式
创建一个潘金莲对象,实现Kindweman接口,同时创建一个代理者王婆也实现这个接口

public class PJL implements  KindWeman{    @Override    public void ShowEyes(Double money) {        System.out.println("PJL 拿到"+money+"元钱,showeyes");    }    @Override    public void DoSe(Double money) {        System.out.println("PJL 拿到"+money+"元钱,Dose");    }}
public class WP implements KindWeman {    private KindWeman kw = null;    public WP(KindWeman kw ){        this.kw = kw;    }    @Override    public void ShowEyes(Double money) {        kw.ShowEyes(money);    }    @Override    public void DoSe(Double money) {        kw.DoSe(money);    }}

潘金莲需要王婆的代理,代理者调用的方法都是被代理者的

public static void main(String[] args){        KindWeman KW = new PJL();        WP p = new WP(KW);        p.ShowEyes(3.0);        p.DoSe(6.0);    }

动态代理
动态代理它可以直接给某一个目标对象生成一个代理对象,而不需要代理类存在。
动态代理与代理模式原理是一样的,只是它没有具体的代理类,直接通过反射生成了一个代理对象。
动态代理生成技术:
1、jdk提供一个Proxy类可以直接给实现接口类的对象直接生成代理对象。
2、cglib (spring框架)

Java.lang.reflect.Proxy类可以直接生成一个代理对象,看例子,这里不需要王婆这个代理者,jdk给我们提供了。

 @Testpublic void test(){    KindWeman kw = new PJL();    //创建一个代理对象    //ClassLoader:类加载器。固定写法,和被代理类使用相同的类加载器即可。kw.getClass().getClassLoader()    //Class[] interface:代理类要实现的接口。固定写法,和被代理类使用相同的接口即可。kw.getClass().getInterfaces()    //InvocationHandler:策略(方案)设计模式的应用。如何代理?即代理的过程,你需要的操作    KindWeman KWproxy = (KindWeman)     Proxy.newProxyInstance(kw.getClass().getClassLoader(), kw.getClass().getInterfaces(), new InvocationHandler() {        @Override        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {            //nvocationHandler中的invoke方法:调用代理类的任何方法,此方法都会执行             //Object proxy:代理对象本身的引用。一般用不着。            //Method method:当前调用的方法。通过反射, KWproxy调用誰,这里的Method就是谁            //Object[] args:当前方法用到的参数            System.out.println("我是中间代理:需要收取费用");            Object o = method.invoke(kw, new Object[]{(Double) args[0] / 2});            System.out.println("事务完成,下次再来!");            return o;        }    });    KWproxy.ShowEyes(6.0);    KWproxy.ShowEyes(3.0);}

这里写图片描述
使用这个思想,在我们前面讲到的业务层调用ThreadLocal管理,就不必要在servce层面上编写了。编写一个类来动态的获取服务,然后在代理当中添加ThreadLocal类实现事务的功能

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import com.itheima.service.AccountService;import com.itheima.service.impl.AccountServiceImpl;public class ObjectFactory {    //方法返回一个代理对象    public static AccountService getAccountService(){        final AccountService  as= new AccountServiceImpl();         AccountService proxy = (AccountService) Proxy.newProxyInstance(as.getClass().getClassLoader(), as.getClass().getInterfaces(), new InvocationHandler() {            public Object invoke(Object proxy, Method method, Object[] args)                    throws Throwable {                Object invoke = null;                try {                    ManagerThreadLocal.startTransacation();//begin                    //执行的是真实对象的转账方法                    invoke = method.invoke(as, args);                    ManagerThreadLocal.commit();//提交事务                } catch (Exception e) {                    try {                        ManagerThreadLocal.rollback();//回滚事务                    } catch (Exception e1) {                        e1.printStackTrace();                    }                 }finally{                    try {                        ManagerThreadLocal.close();                    } catch (Exception e) {                        e.printStackTrace();                    }//关闭                }                return invoke;            }        });        return proxy;       }}
public void transfer(String fromname, String toname, double money) throws Exception {    //  ad.updateAccount(fromname, toname, money);        AccountDao ad = new AccountDaoImpl();            //分别得到转出和转入账户对象            Account fromAccount = ad.findAccountByName(fromname);            Account toAccount = ad.findAccountByName(toname);            //修改账户各自的金额            fromAccount.setMoney(fromAccount.getMoney()-money);            toAccount.setMoney(toAccount.getMoney()+money);            //完成转账操作            ad.updateAccout(fromAccount);        int i = 10/0;            ad.updateAccout(toAccount);    }
0 0
原创粉丝点击