美文网首页
学习笔记:设计模式之代理模式

学习笔记:设计模式之代理模式

作者: 大力papa | 来源:发表于2020-09-30 15:34 被阅读0次

本文仅供学习交流使用,侵权必删。
不作商业用途,转载请注明出处

WHAT 什么是代理模式

代理UML.png

代理模式(Proxy Design Pattern)就是在不修改原来代码的情况下,通过增加一个代理类增强原来的功能代码。代理模式提高了代码的扩展性,需要增加非功能性需求的时候,只需要将这部分逻辑在代理类中实现即可,无需修改原来的代码,符合开闭原则。

代理模式和装饰器区别

装饰器与代理看起来非常相似,但从语义上理解其实并不相同。装饰器的增强代码是与原业务逻辑相关的,例如在原来需求上添加新逻辑。代理的增强代码是与业务逻辑不相关的,例如日志记录,事务,鉴权等。

动态代理

假设对每个接口都添加一层代理做日志或者统计,那么每个接口都需要添加一个代理类。如果接口数量较多,代理类个数也会非常多且不易维护,而且代理类中的代码重复度极高,需求稍作变动就需要修改所有的代理类,很显然这种方式是有问题的。
这种问题我们可以使用动态代理来解决。动态代理就是不事先为每个接口编写代理类,而是在运行时动态创建接口对应的代理类代替原来的接口。而Java语言本身就可以通过反射机制实现动态代理。

WHY 为什么使用代理模式

  • 提高扩展性,符合开闭原则
  • 符合单一职责,业务代码无需加入一些非功能性需求的代码

HOW 代理模式的实现(JAVA)

代理类通常需要实现与被代理类相同的接口或者继承被代理类。这里只实现接口方式以及java动态代理方式

接口实现代理方式

场景:数据获取接口,在获取数据前添加一个代理作为缓存,每次调用数据接口先在缓存中查询是否有数据,无需每次都将请求打到数据库,缓解数据库压力

  • 数据接口
import java.util.List;

public interface IDataService {
    List getData(String id, boolean cache);
}
  • 数据接口实现类
import java.util.Arrays;
import java.util.List;

public class DataServiceImpl implements IDataService {
    @Override
    public List getData(String id, boolean cache) {
        return Arrays.asList("100", "1000", "10000");
    }
}
  • 缓存代理类
public class DataCacheProxy implements IDataService {
    /**
     * 被代理类
     */
    private IDataService dataService;
    /**
     * 缓存表
     */
    private Map<String, List> cacheMap = new HashMap<>();

    public DataCacheProxy(IDataService dataService) {
        this.dataService = dataService;
    }

    /**
     * @param id
     * @param cache 是否需要查询缓存
     * @return
     */
    @Override
    public List getData(String id, boolean cache) {
        if (cache) {
            List lst = cacheMap.get(id);
            if (lst != null && !lst.isEmpty()) {
                System.out.println("cache return data");
                return lst;
            }
        }
        List lst = dataService.getData(id, false);
        cacheMap.put(id, lst);
        return lst;
    }
}
  • 客户端
import java.util.Arrays;
public class ProxyClientMain {
    public static void main(String[] args) {
        IDataService agent = new DataCacheProxy(new DataServiceImpl());
        System.out.println("第一次请求:" + Arrays.toString(agent.getData("1", true).toArray()));
           /*
           第二次从缓存中读取数据
           从控制台打印结果中可以看到第二次的请求是从缓存表中读取数据并返回
            */
        System.out.println("第二次请求:" + Arrays.toString(agent.getData("1", true).toArray()));
    }
}

动态代理

场景: 增加一个计数器,统计接口调用次数

  • 业务接口
import java.util.List;

public interface IBizService {
    List execute();
}
  • 业务接口实现类
import java.util.Arrays;
import java.util.List;

public class BizServiceImpl implements IBizService {
    @Override
    public List execute() {
        return Arrays.asList("hello", "world");
    }
}
  • 代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.atomic.AtomicLong;

public class CounterProxy {

    private static final AtomicLong COUNTER = new AtomicLong(0);

    public Object createProxy(Object serivce) {
        Class[] interfaces = serivce.getClass().getInterfaces();
        DynamicProxyHandler handler = new DynamicProxyHandler(serivce);
        return Proxy.newProxyInstance(serivce.getClass().getClassLoader(), interfaces, handler);
    }

    private class DynamicProxyHandler implements InvocationHandler {
        private Object bizService;

        public DynamicProxyHandler(Object bizService) {
            this.bizService = bizService;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            long count = COUNTER.addAndGet(1);
            try {
                Object result = method.invoke(bizService, args);
                System.out.println("调用次数:" + count);
                return result;
            } catch (Exception e) {
                System.err.println();
            }
            return null;
        }
    }
}
  • 客户端
public class DynamicProxyClientMain {
    public static void main(String[] args) {
        CounterProxy counterProxy = new CounterProxy();
        IBizService bizService = (IBizService) counterProxy.createProxy(new BizServiceImpl());
        for (int i = 0; i < 10; i++) {
            System.out.println(Arrays.toString(bizService.execute().toArray()));
        }
    }
}

相关文章

  • Proxy 代理模式

    设计原则学习笔记 设计模式学习笔记 作用 为对象提供增强作用 类图 图为静态代理。另有动态代理模式,由于类图不具...

  • 设计模式之代理模式

    title: 设计模式之代理模式date: 2018-08-15 20:25:42tags: 设计模式 笔记 Ja...

  • 26 Java设计模式系列-代理模式

    代理模式 代理模式是非常常见的设计模式之一,写个笔记,记录一下我的学习过程和心得。 首先了解一些代理模式的定义。 ...

  • 学习笔记:设计模式之代理模式

    本文仅供学习交流使用,侵权必删。不作商业用途,转载请注明出处 WHAT 什么是代理模式 代理模式(Proxy De...

  • 设计模式系列笔记-代理模式

    写在前面:本系列文章内容为《JavaScript设计模式与开发实践》一书学习笔记,感谢作者曾探 代理模式 代理模式...

  • 设计模式之代理模式

    设计模式之代理模式 10分钟看懂动态代理设计模式(升级篇)-对这篇动态代理模式的思路整理 仿JDK实现动态代理逻辑...

  • 结构型模式--代理模式&&适配器模式&&装饰器模式

    算是读书笔记吧 极客时间--设计模式之美 代理模式和装饰器模式的在实现上相同,所以放在一起看。 以代理模式为例 二...

  • 代理模式

    设计模式之代理模式 什么是代理模式? 指的事代理对象为其他对象提供代理以控制对被...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

  • Java代理模式之JDK动态代理

    了解什么是动态代理模式,可参考Java设计模式之代理模式 简介 JDK动态代理是java.lang.reflect...

网友评论

      本文标题:学习笔记:设计模式之代理模式

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