代理模式和原理

代理模式是一种设计模式,用于在客户端和目标对象之间创建中介,以控制对目标对象的访问。它包括抽象角色、代理角色和真实角色。代理角色通常包含对真实对象的引用,并提供与真实对象相同的方法,同时可以添加额外的操作。动态代理则利用InvocationHandler和Proxy在运行时创建代理实例,当调用代理对象的方法时,实际上会转为调用InvocationHandler的invoke方法。这种模式在实际应用中,如Java中,常用于在方法调用前后添加额外的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基本概念:

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

      上述说法有些抽象,其实跟跟买二手房要通过中介、 买股票要通过券商一样,  买卖双方要通过中介、券商交易, 即中间隔了一层,  这就是代理。


涉及的角色:

1、抽象角色:声明真实对象和代理对象的共同接口。 

2、代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的借款以便在任何时刻都能够代替真实对象。

     同事,代理对象可以对真实对象操作时,附加其它的操作,相当于对真实对象的封装。 (这里可以干坏事,比如雁过拔毛之类的

3、真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。


静态代理:

public interface Shop {
        public void buy(int count);
    }

    public class RealShop implements Shop {
        private int mTotal;  //总共有多少钱

        public RealShop(int total) {
            mTotal = total;
        }

        @Override
        public void buy(int count) {
            System.out.println("消费了" + count);
            mTotal = mTotal - count;
        }
    }

    public class ProxyShop implements Shop {
        private Shop mShop;   //指向被调用的对象
        public ProxyShop(Shop shop) {
            mShop = shop;
        }

        //代理模式写法
        public void buy(int count) { //代理模式对引用对象有控制权, 即可以不调用原函数
            if (count > 100) {
                mShop.buy(count);   //真正干活
            } else {
                //静态代理模式可以不调用被引用对象的方法
                //但装饰者模式必须调用
            }

            //因为拿到了被调用对象的引用, 这里可以添油加醋!
            mShop.buy(50);  //雁过拔毛, 我拿到你的引用了,想干什么都可以!
        }
        
        //装饰者模式写法, 
        /*
        public void buy(int count) { 
            mShop.buy(count);   //真正干活

            //do something
            System.out.pringln("test");  //加点料就是装饰者模式的作用
        }
        */
    }
   PS: 静态代理模式和装饰者模式基本一致, 唯一的区别在于代理模式有控制权, 可以不使用被引用对象。 装饰者模式必须调用被引用对象; 如上面例子中count>100的条件, 可以不调用引用对象的buy方法。


动态代理:

使用InvocationHandler和Proxy在程序运行时替换实例。 每一个动态代理类都要实现InvocationHandler这个借口,  并且每个代理类的实例都关联到一个Handler, 当我们通过代理对象调用一个方法的时候, 这个方法的调用就会被转发为由InnovationHandler这个接口的invoke方法来进行调用。

public interface InvocationHandler {
    /* Processes a method invocation on a proxy instance and returns the result. This method will be invoked on an invocation handler when a method is invoked on a proxy instance that it is associated with.  */
     public Object  invoke(Object proxy, Method method, Object[] args)
}


       实际验证, 在执行shop.buy(99)这条语句时, 执行了ShopHandler的invoke函数, 而不是RealShop的buy方法。

 public static void main(String[] args) {
        Shop realshop = new RealShop(1000);
        InvocationHandler handler = new ShopHandler(realshop);

        Shop shop = (Shop) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
                realshop.getClass().getInterfaces(), handler);
        System.out.println(shop.getClass().getName());
        shop.buy(99);   //消费99
    }

    public static class ShopHandler implements InvocationHandler {
        private Object mObj; //要代理的真实对象

        public ShopHandler(Object object) {
            mObj = object;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before do something");
            System.out.println("Method:" + method);

            method.invoke(mObj, args);

            System.out.println("after do something");
            return null;
        }
    }

    public  interface Shop {
         void buy(int count);
    }

    public static class RealShop implements Shop {
        private int mTotal;  //总共有多少钱

        public RealShop(int total) {
            mTotal = total;
        }

        @Override
        public void buy(int count) {
            System.out.println("do shop, buy:" + count);
            mTotal = mTotal - count;
        }
    }

    public static class ProxyShop implements Shop {
        private Shop mShop;   //指向被调用的对象
        public ProxyShop(Shop shop) {
            mShop = shop;
        }

        @Override
        public void buy(int count) {
            mShop.buy(count);   //真正干活

            //因为拿到了被调用对象的引用, 这里可以添油加醋!
            mShop.buy(50);  //雁过拔毛, 我拿到你的引用了,想干什么都可以!
        }
    }

com.sun.proxy.$Proxy0
before do something
Method:public abstract void com.example.MyClass$Shop.buy(int)
do shop, buy:99
after do something

         从日志看出newProxyInstance返回的是com.sun.proxy.$Proxy0类对象。 在main函数里添加一行代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true")后重新编译。

         查看buy函数, 实际上是调用的InnovationHandler的invoke方法。




参考:

https://blog.csdn.net/u011298387/article/details/53508709

https://blog.csdn.net/jiankunking/article/details/52143504


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值