动态代理模式详解

代理模式

代理模式的好处

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

缺点

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

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

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

少废话直接上代码

先来一个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();
    }
}

总结

posted @ 2020-04-12 21:04  三毛是学IT掉发的  阅读(331)  评论(0编辑  收藏  举报