zoukankan      html  css  js  c++  java
  • 动态代理模式详解

    代理模式

    代理模式的好处

    • 可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
    • 公共也就是交给代理角色,实现了业务的分工
    • 公共业务发生扩展的时候,方便集中管理

    缺点

    • 一个真是的角色会产生一个代理觉得:代码量翻倍,开发效率降低

    下面用房子出租案例说明代理模式

    房东出租房子,真实角色比如(你)要租房子,房东出租房子要贴广告啊,发布信息啊,找到租户之后还要谈价格签合同啊,房东作为包租婆太懒了,这点小活都不愿意干,于是,她把这个任务交给你了中介,让中介来帮他寻找需要租房子的客户等等一些杂七杂八的活,而他只需要在家吃着西瓜追剧就行啦。而真实客户呢,要想要租房,那就必须得跟中介谈。

    少废话直接上代码

    先来一个Rent接口,因为各方都需要租房这个业务,面向接口编程啦

    public interface Rent {
        public void rent();
    }
    

    房东要出租了,中介你帮我骗几个大学生过来租房子

    public class Host implements Rent {
        public void rent(){
            System.out.println("我要出租房子");
        }
    

    中介想要挣钱,必须要收中介费,不然我干嘛要帮你干活

    public class Proxy implements Rent {
        private Host host;
        public Proxy(){
    
        }
        public Proxy(Host host){
            this.host=host;
        }
        public void rent(){
            host.rent();
            seeHouse();
            goodHouse();
            heTong();
            proxyMoney();
           
        }
        public void seeHouse(){
            System.out.println("带你去看房子!");
        }
        public void goodHouse(){
            System.out.println("这个房子好啊~");
        }
        public void heTong(){
            System.out.println("签立合同!");
        }
        public void proxyMoney(){
            System.out.println("你要交中介费");
        }
    }
    

    你要租房

    public class Client {
        public static void main(String[] args) {
            //代理模式
            Host host=new Host();
            Proxy proxy=new Proxy(host);
            proxy.rent();
        }
    }
    

    看到这里相信你对代理模式有点熟悉了吧,接下来用一个业务的代码带你再次了解静态代理的思路

    • 假如有一个实现了增删改查的业务代码,现基础上要添加一个log4j的功能,要求不能改动原有的业务代码。这时候就能发挥到静态代理的功能性了
    • 啥也别说了,上代码

    老套路,来一个接口,然后实现它

    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void select();
    }
    

    实现增删改查的功能

    public class UserServiceImpl implements UserService {
        public void add() {
            System.out.println("add");
    
        }
    
        public void delete() {
            System.out.println("delete");
    
        }
    
        public void update() {
            System.out.println("update");
        }
    
        public void select() {
            System.out.println("select");
        }
    }
    
    

    重点来了,这时候要扩展一个新的功能,不能改变原来的业务代码,就得用代理

    public class UserServicePrexy implements UserService{
        private UserServiceImpl userService;
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
        public void add() {
            log4j("add");
            userService.add();
        }
        public void delete() {
            userService.delete();
        }
        public void update() {
            userService.update();
        }
        public void select() {
            userService.select();
        }
        public void log4j(String mes ){
            System.out.println("使用了"+mes+"方法");
        }
    }
    

    添加了一个log4j日志功能,原来的UserServiceImpl没有改动代码

    实例

    public class Client {
        public static void main(String[] args) {
            UserServiceImpl userService=new UserServiceImpl();
            UserServicePrexy userServicePrexy=new UserServicePrexy();
            userServicePrexy.setUserService(userService);
            userServicePrexy.add();
    
        }
    }
    

    到这里就很清楚的明白代理模式的思路了吧。

    总结一下:

    • 代理模式可以使真是角色的操作更加纯粹!不用去关注一些公共的业务
    • 公共也就是交给代理角色,实现了业务的分工
    • 代理是一种设计的思想,提供了间接对目标对象进行访问的方式;即通过代理访问目标对象,可以在目标对象中进行实现功能,增加额外的功能,扩展性高,符合了设计模式的开闭原则,即是在对原有的代码不改动下,进行功能扩展

    说完了静态代理,我们来说说动态代理

    *上面说了静态代理有一个缺点:
    一个真是的角色会产生一个代理觉得:代码量翻倍,开发效率降低

    能不能实现一个更好的代理模式呢?既能满足功能的扩展还能使得开发效率高效呢?这时候动态代理出现了~~~

    动态代理

    • 动态代理和静态代理角色是一样的

    • 动态代理的代理类是动态生成的,不是我们自己写好的

    • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

      • 基于接口-----jdk 动态代理

      • 基于类:cglib

        动态代理的实现有很多种 但是思想都是一样的,这里我们用的是基于接口实现的 ---jdk动态代理实现

    基于接口实现代理,要用到两个核心类:Proxy : 代理类 InvocationHandler :调用处理程序

    InvocationHandler 是java.lang.refect下的类。是由代理实例的,调用处理程序实现的接口。每个代理实例都有一个关联的调用处理程序,当代理实例上调用方法时,方法调用将编码并分派其调用处理程序的invoke方法。也就是说我们要实例一个代理类,要先实现这个接口,这接口能动态帮我们生成代理类

    话不多说,上代码

    老样子,接口

    public interface Rent {
        public void rent();
    }
    

    实现接口

    public class Host implements Rent{
        public void rent() {
            System.out.println("我要出租房子");
        }
    }
    
    

    实现InvocationHandler 类,用这个类能够帮我们动态生成代理

    public class ProxyInvocationHandler implements InvocationHandler {
        private Object target;
    
        public void setTarget(Object target) {
            this.target = target;
        }
        //生成代理类
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    
        //处理代理类的实例,返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            Object result= method.invoke(target,args);
            return result;
        }
    }
    

    测试

    public class Client {
        public static void main(String[] args) {
            //被代理的类
            Host host=new Host();
            //ProxyInvocationHandler类并不是代理类,它只是一个能够动态生成代理类的工具
            ProxyInvocationHandler proxyInvocationHandler=new ProxyInvocationHandler();
            //通过调用程序处理角色来处理我们要调用的接口
            proxyInvocationHandler.setTarget(host);
            //返回代理类,这里getProxy()才是真正的创建出代理类
            Rent proxy =(Rent) proxyInvocationHandler.getProxy();
            proxy.rent();
        }
    }
    

    总结

  • 相关阅读:
    初始化注解和销毁注解
    MySQL、SQLServer、Oracle 分组排序
    mybatis 中SQLServer 和 mysql 模糊查询 不同点
    SpringBoot学习之logback.xml 配置指定包或类输出至单独的日志文件中
    类比 RocketMq 和 淘宝消息服务:
    SVN提交文件失败:系统找不到指定路径
    官网下载MySQL 并安装
    Java 变量参数传入方法,方法结束后传入的值
    03-类与对象课后作业(1)
    02方法-课后动手动脑
  • 原文地址:https://www.cnblogs.com/myblogswcz/p/12687624.html
Copyright © 2011-2022 走看看