美文网首页
代理模式

代理模式

作者: 涛涛123759 | 来源:发表于2021-05-09 20:16 被阅读0次

    Android知识总结

    一、使用场景

    • 当一个对象不能或者不想直接访问另一个对象时,可以通过一个代理对象来间接访问。为保证客户端使用的透明性,委托对象和代理对象要实现同样的接口。
    • 被访问的对象不想暴露全部内容时,可以通过代理去掉不想被访问的内容。
    • Interface: 抽象接口,声明真是主体与代理主题的共同接口方法。
    • RealSubject: 真实主题类,定义了代理所表示的真是对象,执行具体的业务方法。客户端通过代理类来间接的调动这个真实主题中的方法。
    • ProxySubject: 代理类,持有一个真实类的引用,在接口方法中调用真实主题相应的方法,达到代理的作用。

    注释:通过代理使client和真实对象隔离,使用户不用操作真实对象只用操作代理类就可达到指定效果。

    二、静态代理

    public interface ILawsuit {
        void submit();//提交申请
        void burden();//进行举证
        void defend();//开始辩护
        void finish();//诉讼完成
    }
    
    public class Civilian implements ILawsuit {
        @Override
        public void submit() {
            System.out.println("起诉");
        }
    
        @Override
        public void burden() {
            System.out.println("举证");
        }
    
        @Override
        public void defend() {
            System.out.println("辩护");
        }
    
        @Override
        public void finish() {
            System.out.println("胜诉");
        }
    }
    
    public class Lawyer implements ILawsuit {
        private ILawsuit civilian;
    
        public Lawyer(ILawsuit civilian) {
            this.civilian = civilian;
        }
    
        @Override
        public void submit() {
            civilian.submit();
        }
    
        @Override
        public void burden() {
            civilian.burden();
        }
    
        @Override
        public void defend() {
            civilian.defend();
        }
    
        @Override
        public void finish() {
            civilian.finish();
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            ILawsuit civilian = new Civilian();
            ILawsuit lawyer = new Lawyer(civilian);
            lawyer.submit();
            lawyer.burden();
            lawyer.defend();
            lawyer.finish();
        }
    }
    

    缺点:扩招能力差和可维护性差。违反开闭原则。

    三、动态代理

    动态代理通过反射动态的生成代理者对象(代理类 ProxySubject),也就是说在写代码的时候根本不知道要代理谁,具体代理谁会在执行阶段决定。

    Java提供了一个便捷的动态代理接口InvocationHandler,动态代理类只要实现这个接口就行:

    public class DynamicProxy implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            return null;
        }
    }
    

    看一下动态代理的用法:

    public class DynamicProxy implements InvocationHandler {
        private Object object;
    
        public DynamicProxy(Object object) {
            this.object = object;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //当然这里可以对方法名进行判断过滤 if(method.getName().equals("***"))
            Object result = method.invoke(object,args);
            return result;
        }
    }
    

    客户端调用:
    java

    public class Main {
        public static void main(String[] args) {
            ILawsuit lawsuit = new Civilian();
            DynamicProxy proxy = new DynamicProxy(lawsuit);
            ClassLoader loader = lawsuit.getClass().getClassLoader();
            //动态创建代理类,需要传入一个类加载器ClassLoader;一个你希望这个代理实现的接口列表,这里要代理ILawsuit接口;
            //第一个参数是ClassLoader; 第二个参数是生成代理类指定接口的Class数组;第三个参数是InvocationHandler的实现
            ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ILawsuit.class}, proxy);
            lawyer.submit();
            lawyer.burden();
            lawyer.defend();
            lawyer.finish();
        }
    }
    

    kotlin

    object MainTest{
        @JvmStatic
        fun main(argc : Array<String>){
            val lawsuit = Civilian()
            val messageInterface = Proxy.newProxyInstance(MainTest::class.java.classLoader,
                arrayOf<Class<*>>(ILawsuit ::class.java) 
            ) { _, method, args -> method!!.invoke(lawsuit , *args) } as ILawsuit 
            messageInterface.setName("小米", 13)
        }
    }
    
    
    • out 和 in 代表 extends 和 super;out T 等价于 ?extends T
      ;in T等价于 ? super T
    • Class< * >:*号等于Java的Class< ? >
    • *args:等于Java中的可变参数(Object... args)。如下代码:
    public class CallJavaUtils {
    
        public static int addNumbers(String name, int... args) {
            int result = 0;
            for (int i = 0; i < args.length; i++) {
                result += args[i];
            }
            return result;
        }
    }
    
    //测试Kotlin传递可变长参数给Java可变参数方法
    var numbers:IntArray = intArrayOf(1, 2, 3, 4, 5)
    CallJavaUtils.addNumbers("add", *numbers)
    

    代理类进一步封装

    public class DynamicProxy implements InvocationHandler {
        /*持有的真实对象*/
        private Object factory;
    
        public DynamicProxy(Object factory) {
            this.factory = factory;
        }
    
        public Object getFactory() {
            return factory;
        }
    
        public void setFactory(Object factory) {
            this.factory = factory;
        }
    
        /**
         * 获取代理对象
         *
         * @return
         */
        private Object getProxyInstance() {
            return Proxy.newProxyInstance(factory.getClass().getClassLoader(),
                    factory.getClass().getInterfaces(), this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            doSthBefore();
            Object invoke = method.invoke(factory, args);
            doSthAfter();
            return invoke;
        }
    
        /**
         * 后置处理器
         */
        private void doSthAfter() {
            System.out.println("method after do something.");
        }
    
        /**
         * 前置处理器
         */
        private void doSthBefore() {
            System.out.println("method before do something.");
        }
    }
    

    缺点:运用反射技术使执行效率较差。

    四、其他分类

    静态代理和动态代理是从code方便进行分类的。这两个分类根据适用范围来分都可以分为下面几种:

    • 远程代理:为摸个对象在不同的内存地址空间提供局部代理,是系统Server部分隐藏,以便Client不用考虑Server的存在。
    • 虚拟代理:如果要创建一个资源消耗较大的对象,可以先用一个代理对象表示,在真正需要的时候才真正创建。
    • 保护代理:用代理对象控制对一个对象的访问,给不同的用户提供不同的访问权限。
    • 智能引用:在引用原始对象的时候附加额外操作,并对指向原始对象的引用增加引用计数

    相关文章

      网友评论

          本文标题:代理模式

          本文链接:https://www.haomeiwen.com/subject/ygmzmftx.html