Android中的代理模式

Android中的代理模式

1. 什么是代理

 比如我们生活中的找出租屋,需要去找中介进行寻找挑选.
 而这里的中介就是代理.
 列子中看出代理特点如下
 	1. 租客跟中介要做成的最终目的是一致的就是租到房子(目标一致).
 	2. 中介资源多,有权利跟房东进行价格协商(功能强大).
 	3. 中介是不会让我们直接跟房东进行协商(无法直接访问到目标). 
 
 我们在开发中也是有相似的情况出现
 你有个a类,本来是调用c类方法,完成某个功能.但是c类不让a直接调用.
 	a-->不能直接调用c的方法
 在a和c之间直接创建一个b代理类,c让b访问.
 	a-->访问b方法-->访问c方法 	 		

在这里插入图片描述
总结:我们在开发中使用代理模式是为了在不修改目标对象的基础上,增强主业务逻辑,客户类真正的想要访问的对象是目标对象,但是客户类真正可以访问的对象是代理对象.
在这里插入图片描述

2. 代理模式的作用

1.功能增强:在原有的功能上,增加额外的功能.
2.控制访问:代理类不让你访问到目标类.

3. 实现代理的方式-静态代理

1.自己手工实现的代理类.
2.代理的目标类是固定的.
特点:实现简单,容易理解.
举例子:
用户买鞋子行为
用户(客户端)-----商家(代理类)-----厂家(目标类)
其中,商家和厂家都是卖鞋子的,他们的完成的功能是一致的都是卖鞋子

    interface IShoesSell {
        //num 购买的数量 返回值是一双鞋子的价格
        public float sell(int num);
    }

    //特步厂家
    public class TebuShoesSellimpl implements IShoesSell {
        @Override
        public float sell(int num) {
            return 300.0f;
        }
    }

    //京东商家
    public class JD implements IShoesSell {

        private IShoesSell mFactory = new TebuShoesSellimpl();

        @Override
        public float sell(int num) {
            float price = mFactory.sell(num);
            price += 25;
            return price;
        }
    }


    public  void main(String[] args) {
        //创建代理对象-JD 进行购买
        JD jd =new JD();
        jd.sell(1); //这里我们就是通过京东购买了特步的鞋子325块
    }

我们可以在JD类sell方法进行功能增强(添加优惠券,满减等),也不难发现我们JD类里面的目标类是固定的(特步厂家TebuShoesSellimpl).

多添加厂家和商家代码的情况:

    //京东商家
    public class JD implements IShoesSell {

        private IShoesSell mFactory = new TebuShoesSellimpl();

        @Override
        public float sell(int num) {
            float price = mFactory.sell(num);
            price += 25;
            return price;
        }
    }
    //拼多多商家
    public class PDD implements IShoesSell {

        private IShoesSell mFactory = new TebuShoesSellimpl();

        @Override
        public float sell(int num) {
            float price = mFactory.sell(num);
            price -= 25;
            return price;
        }
    }
	//安踏厂家
    public class AntaShoesSellimpl implements IShoesSell {
        @Override
        public float sell(int num) {
            return 350.0f;
        }
    }
	
	//京东商家-安踏
    public class JDAnta implements IShoesSell {

        private IShoesSell mFactory = new AntaShoesSellimpl();

        @Override
        public float sell(int num) {
            float price = mFactory.sell(num);
            price += 25;
            return price;
        }
    }


    //拼多多商家-安踏
    public class PDDAnta implements IShoesSell {

        private IShoesSell mFactory = new AntaShoesSellimpl();

        @Override
        public float sell(int num) {
            float price = mFactory.sell(num);
            price -= 25;
            return price;
        }
    }
    //这里就带来一个问题我只要添加一个目标类(安踏厂家),那我的代理类(商家)都要对应添加类,会出现一对n的变化,增加代码维护成本.

在这里插入图片描述
缺点:

  1. 目标类增多对应的代理类成倍增加.
  2. 当接口的方法进行添加修改时,会影响到众多类实现类需要修改,大大增加出错率.

4. 实现代理的方式-动态代理

优点:

  1. 代理类数量可以很少.
  2. 当你修改了接口中的方法时,不会影响代理类.

概念:
在程序执行过程中,使用jdk的反射机制,创建代理类对象,并动态的制定要代理目标类.
理解:
正常我们在java中想要创建对象是需要两个步骤

  1. 创建类文件,java文件编译成class文件.
  2. 使用构造方法new JD() ,创建类的对象.

动态代理直接是第二步骤(创建类的对象),跳过类文件创建.(so 文件少的原因)
动态代理的实现需要掌握的类(java.lang.reflect):

  1. InvocationHandler:
    接口,invoke方法里面填写功能代码
public Object invoke(Object proxy, Method method, Object[] args);
  1. Method:
    类中的方法,通过Method对象就可以执行某个方法. (invoke方法)
public native Object invoke(Object obj, Object ... args) 
  1. Proxy:
    核心的对象,主要是创建代理对象.使用newProxyInstance()代替new.
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

实现动态代理完整代码

   IShoesSell mFactory = new TebuShoesSellimpl(); //特步厂家
// IShoesSell mFactory = new AntaShoesSellimpl(); //安踏厂家
   IShoesSell proxy = (IShoesSell)Proxy.newProxyInstance(mFactory.getClass().getClassLoader(), mFactory.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                float price = (float) method.invoke(mFactory, args);
                price += 30;// 京东代理
                //price -= 25; 拼多多代理
                return price;
            }
        });
   proxy.sell(1);

下面是实际的项目中的运用–获取项目中metaData数据进行修改
通过源码发现metadata 在ApplicationInfo中metaData属性.

private static void hookPM( ) {
        try {
            //获取ActivityThread对象
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Field field = activityThreadClass.getDeclaredField("sCurrentActivityThread");
            field.setAccessible(true);
            Object activityThread = field.get(null);

            //获取了PackageManager对象
            Method getPackageManager = activityThread.getClass().getDeclaredMethod("getPackageManager");
            getPackageManager.setAccessible(true);
            Object iPackageManager = getPackageManager.invoke(activityThread);

            //获取IPackageManager接口的Class对象
            Class<?> iPackageManagerClass = Class.forName("android.content.pm.IPackageManager");

            //生成动态代理类
            Object pmProxy = Proxy.newProxyInstance(
                    Thread.currentThread().getContextClassLoader(), //加载代理类的类加载器
                    new Class[]{iPackageManagerClass}, //代理类需要实现的接口 (需要实现被代理类的接口)
                    (proxy, method, args) -> { // 当被代理类的接口实现方法被调用时,会回调此实现类的invoke()方法,该方法中应该保证被代理类的原逻辑的执行(即 return时的调用)
                        //ApplicationInfo
                        if (method.getName().equals("getApplicationInfo")) {
                            ApplicationInfo invoke = (ApplicationInfo) method.invoke(iPackageManager, args);
                            if (invoke.metaData == null) {
                            } else {
                                Bundle metaData = invoke.metaData;
                                metaData.putString("BD_KEY", "fdfdfdfffff");
                                metaData.putString("GD_KEY", "fffffsdssss");
                            }
                            return invoke;
                        } else {
                            return method.invoke(iPackageManager, args);
                        }

                    });
            Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager");
            sPackageManagerField.setAccessible(true);
            sPackageManagerField.set(activityThread, pmProxy);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

5. 总结

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值