• 设计模式随笔(六):代理模式


    概念:

    什么是代理模式: 为其他对象提供一种代理,来控制对这个对象的访问;有些情况下一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

    作用

    1.隐藏委托类的具体实现

    2.实现客户端和委托类的解耦,不改动委托类的情况下增加功能(如日志)

    类图

    以去超市买东西为例

    静态代理:

    预先就确定了代理和被代理对象间的关系,在编程中指编译前,代理类和被代理类的关系已经确定了;

    /**
     * 委托类和代理类都实现了factory接口
     **/
    public interface Factory {
    
        void sell();
    
        void ad();
    
    }
    public class Shop implements Factory {
    
        private Factory factory;
    
        public Shop(Factory factory) {
            this.factory = factory;
        }
    
        @Override
        public void sell() {
            System.out.println("商店代理销售");
            factory.sell();
        }
    
        @Override
        public void ad() {
            System.out.println("商店代理广告");
            factory.ad();
        }
    }
    public class Vendor implements Factory {
        @Override
        public void sell() {
            System.out.println("供应商销售产品");
        }
    
        @Override
        public void ad() {
            System.out.println("供应商打广告");
        }
    }
    public class Client {
    
        public static void main(String[] args) {
            // 供应商---被代理类
            Vendor vendor = new Vendor();
            // 创建供应商的代理类Shop
            Factory shop = new Shop(vendor);
            // 客户端使用时面向的是代理类Shop。
            shop.sell();
    
            shop.ad();
    
        }
    
    }

    动态代理:

    静态代理每个代理类都必须实现代理接口,如果业务很多,会导致类迅速膨胀,为了避免这点,java基于反射提供了动态代理,实现方式常见的有两种

    1.JDK提供的InvocationHandler接口和java.lang.reflect包下的Proxy类

    2.cglib实现的动态代理

    基于动态代理,无论业务接口和委托类如何变化,代理类都可以不变化。

    基于InvocationHandler接口

    代理类和委托对象实现同一接口

    public interface User {
        void login(String userName, String pwd);
        void logout(String userName);
    }

    实现类:

    public class UserImpl implements User {
        @Override
        public void login(String userName, String pwd) {
            System.out.println("用户名:" + userName + ",登录成功");
        }
    
        @Override
        public void logout(String userName) {
            System.out.println("用户名:" + userName + ",注销");
        }
    }

    代理类:

    public class UserDynamicProxy implements InvocationHandler {
    
        // 代理对象
        private Object target;
    
        public <T> T getProxyInstance(Object target) {
            // 委托对象,真正的业务对象
            this.target = target;
            // 获取Object类的ClassLoader
            ClassLoader cl = target.getClass().getClassLoader();
            // 获取接口数组
            Class<?>[] cs = target.getClass().getInterfaces();
            // 获取代理对象并返回
            return (T) Proxy.newProxyInstance(cl, cs, this);
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            Object r = method.invoke(target, args);
            return r;
        }
    }

    测试:

    public class DynamicClient {
    
        public static void main(String[] args) {
            // 真实角色,委托人
            User user = new UserImpl();
            // 获取委托对象user的代理对象
            UserDynamicProxy proxy = new UserDynamicProxy();
    
            User userProxy = proxy.getProxyInstance(user);
    
            userProxy.login("a1","abcd");
            userProxy.login("a2","abcd");
            userProxy.login("a3","abcd");
            userProxy.login("a4","abcd");
            userProxy.login("a5","abcd");
            userProxy.logout("a1");
        }
    }

    输出:

    用户名:a1,登录成功
    用户名:a2,登录成功
    用户名:a3,登录成功
    用户名:a4,登录成功
    用户名:a5,登录成功
    用户名:a1,注销

    基于JDK有个前提条件就是“代理对象和委托对象继承同一接口”,如果没有接口怎么办呢?这时候我们可以菜用Cglib实现动态代理。

    基于Cglib

    委托类

    public class UserClient {
        public void login(String userName, String pwd) {
            System.out.println("用户名:" + userName + ",登录成功");
        }
    
        public void logout(String userName) {
            System.out.println("用户名:" + userName + ",注销");
        }
    }

    代理类

    public class UserClientCglibProxy implements MethodInterceptor {
        // 委托对象
        private Object target;
    
        public <T>T getProxyInstance(Object target) {
            this.target = target;
            // 增强类对象
            Enhancer enhancer = new Enhancer();
            // 设置其超类为target的类类型
            enhancer.setSuperclass(this.target.getClass());
            // 回调方法
            enhancer.setCallback(this);
            // 创建代理对象
            return (T)enhancer.create();
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object r = proxy.invokeSuper(obj, args);
            return r;
        }
    }

    测试:

    public class DynamicClient {
    
        public static void main(String[] args) {
    
            UserClient userClient = new UserClient();
            // 获取委托对象user的代理对象
            UserClientCglibProxy userClientCglibProxy = new UserClientCglibProxy();
    
            UserClient userProxy = userClientCglibProxy.getProxyInstance(userClient);
    
            userProxy.login("a1","abcd");
            userProxy.login("a2","abcd");
            userProxy.login("a3","abcd");
            userProxy.login("a4","abcd");
            userProxy.login("a5","abcd");
            userProxy.logout("a1");
        }
    }
  • 相关阅读:
    5月编程语言排行榜:动态语言的前世今生
    编程语言范式
    面向函数范式编程(Functional programming)
    bash脚本测试总结
    BASH的保护性编程技巧
    汇编Shellcode的技巧
    FreeBSD上编写x86 Shellcode初学者指南
    CnAms and cndoc
    Linux下shellcode的编写
    How To Configure NetScaler AppFlow for SolarWinds
  • 原文地址:https://www.cnblogs.com/chylcblog/p/13339753.html
Copyright © 2020-2023  润新知