你了解代理模式了吗??

代理模式应用场景十分广泛,随便一个框架都会用到,因此学好代理模式对后续框架学习是最基本的要素!!今天我们就来讲讲代理模式

目录

  • 1、简介
    • 1. 核心作用
    • 2. 角色分析
    • 2. 应用场景
    • 4. 分类
  • 2、静态代理
    • 1. 案例:房东租房
    • 2. 优劣分析
    • 3. 加深理解
  • 3、动态代理
    • 1. 简介
    • 2. Proxy 类
    • 3. InvocationHandler 接口
    • 4. 代码示例
    • 好处

首先,了解以下23种设计模式中 代理模式的定位,它是 结构性模式
你了解代理模式了吗??_第1张图片

1、简介

Proxy pattern

1. 核心作用

  • 通过代理,控制对对象的访问

    可以详细的访问某个(某类)对象的实现,在调用这个方法前做前置处理,调用这个方法后做后置处理(AOP的微观实现)

  • 代理模式是SpringAOP的核心实现机制!


2. 角色分析

你了解代理模式了吗??_第2张图片

抽象角色

  • 定义代理角色和真实角色的公共对外方法,一般会使用接口或者抽象类来解决

真实角色

  • 实现抽象角色,定义真实角色要实现的业务,供代理角色调用

代理角色

  • 实现抽象角色,代理真实角色,通过真实角色的业务来实现抽象方法,一般会有附属的业务

客户

  • 访问代理角色的人

2. 应用场景

安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。


4. 分类

  • 静态代理(静态定义代理类)
  • 动态代理(动态生成代理类)
    • JDK自带的动态代理
    • javaassist字节码操作库实现
    • CGLIB
    • ASM(底层使用指令,可维护性较差)



2、静态代理

static proxy

1. 案例:房东租房

接下来以房东租房这件实例,来讲讲代理模式

房东租房,如果房东懒得管太多,这时候就需要一个中介,来帮助房东租房并打理一切事情,这时候租房者就不需要直接和房东打交道了,而是通过中介间接和房东打交道,中介就是中间者,代理了房东,且可以在租房前后附加其他操作,比如:签合同,看房子等

你了解代理模式了吗??_第3张图片

这时候对象上述的四个角色就有四个对象

  1. 抽象角色:租房业务
  2. 真实角色:房东
  3. 代理角色:中介,可能还有带客户看房子等业务
  4. 客户:租房者

接下来,我们通过代码还原上述四个角色

  1. 抽象角色:表示租房这个业务,用接口实现

    //租房
    public interface Rent {
        public void rent();
    }
    
  2. 真实角色:代表房东,实现租房业务接口

    //房东
    public class Host implements Rent{
    
        public void rent() {
            System.out.println("房东要出租房子了");
        }
    }
    
  3. 代理角色中介,实现租房业务接口

    因为代理了房东,所以私有属性是房东对象,除了租房子业务外,可能还有看房、签合同、收中介费等业务

    public class Proxy implements Rent {
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        //代理租房子
        public void rent() {
            seeHouse();
            host.rent();
            contract();
            fare();
        }
    
        //看房
        public void seeHouse() {
            System.out.println("中介带你看房");
        }
    
        //签合同
        public void contract() {
            System.out.println("租赁合同");
        }
    
        //收中介费
        public void fare() {
            System.out.println("收中介费");
        }
    }
    
  4. 客户租房者,访问中介

    public class Client {
        public static void main(String[] args) {
            //房东租房子
            Host host = new Host();
            //代理,中介帮房东租房子,并且有一些附属操作
            Proxy proxy = new Proxy(host);
            //不需要找房东,直接找中介租房即可
            proxy.rent();
        }
    }
    
    你了解代理模式了吗??_第4张图片


2. 优劣分析

好处

  1. 职责清晰

    使真实角色更加的简单专一,不管具体的业务

    • 这里房东只用给中介费就行了,其他一切都交给中介来做,实现了业务分工
  2. 智能化

    客户只需访问代理角色,减少了直接访问真实角色带来的问题

    • 加入这里房东有很多房子,自己一个人可能管理不过来,这时候每个客户的体验可能会变差,会出现很多问题
  3. 高拓展性

    业务发展拓展的时候,方便集中管理

缺点

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低


3. 加深理解

可能上述例子过于简单,不能直观的感受到代理模式的好处,我们再举个例子加深理解

首先创建一个业务实现接口

npublic interface UserService {
    public void add();

    public void delete();

    public void update();

    public void query();
}

然后再来一个业务实现类

public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("增加一个用户");
    }

    public void delete() {
        System.out.println("删除一个用户");
    }

    public void update() {
        System.out.println("修改了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
}

再来个测试类

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        userService.add();
        userService.delete();
        userService.update();
        userService.query();
    }
}

如果此时,我们需要增加一个日志业务,需要打印每个方法的执行

  • 普通修改在业务实现类中的每个方法中都要修改
public class UserServiceImpl implements UserService {
    public void add() {
        System.out.println("使用了add方法");
        System.out.println("增加一个用户");
    }

    public void delete() {
        System.out.println("使用了delete方法");
        System.out.println("删除一个用户");
    }

    public void update() {
        System.out.println("使用了update方法");
        System.out.println("修改了一个用户");
    }

    public void query() {
        System.out.println("使用了query方法");
        System.out.println("查询了一个用户");
    }
}

业务很多的情况下,修改量十分大,这时候用代理模式就能很好的解决我们的问题

我们新建一个业务代理类,在业务实现类里只需增加一个方法就可以实现上述新增业务

public class UserServiceProxy implements UserService {
    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void add() {
        log("使用了add方法");
        userService.add();
    }

    public void delete() {
        log("使用了delete方法");
        userService.delete();
    }

    public void update() {
        log("使用了update方法");
        userService.update();
    }

    public void query() {
        log("使用了query方法");
        userService.query();
    }

    public void log(String msg) {
        System.out.println("使用了" + msg + "方法");
    }
}

然后修改测试类,进行测试

package demo2;

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.query();
    }
}
你了解代理模式了吗??_第5张图片

由此可见

  • 当业务需要拓展的时候,代理模式充分的体现了其高拓展性
  • 业务很多的时候,代理模式也方便管理



3、动态代理

dynamic proxy

1. 简介

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 分类
    • JDK自带的动态代理
    • javaassist字节码操作库实现
    • CGLIB
    • ASM(底层使用指令,可维护性较差)

接下来我们讲述JDK自带的动态代理

需要了解:Proxy(代理)、InvocationHandler(调用处理程序)

2. Proxy 类

代理
你了解代理模式了吗??_第6张图片

  • 都是静态方法,直接通过类名调用
  • 作用:动态生成代理类和对象

所有方法
你了解代理模式了吗??_第7张图片
创建动态类的方法:【重要】

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)

每次通过Proxy生成的代理类对象都要指定对应的处理器对象,就是第三个参数

三个参数

  • 类加载器,来定义代理类
  • 代理类实现的接口列表
  • 处理器接口对象

3. InvocationHandler 接口

处理器接口
你了解代理模式了吗??_第8张图片

  • 通过invoke方法实现对真实角色的访问(就是调用真实角色的方法)

唯一的一个方法
image-20200808153905412
三个参数

  • proxy:代理类
  • method:正在调用的方法
  • args:方法中的参数,默认即可

4. 代码示例

这里还是以上述租房子为实例,我们用动态代理的方式实现

Rent接口(抽象角色) 和 Host类(真实角色)不变

  1. 定义一个处理器接口实现类,继承InvocationHandler
    你了解代理模式了吗??_第9张图片
    其中的invoke方法实现对真实角色方法的调用,因此该类中有真实角色私有属性,为传参使用

    package demo3;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class ProxyInvocationHandler implements InvocationHandler {
        //定义真实角色
        private Rent host;
    
        //真实角色set方法
        public void setHost(Rent host) {
            this.host = host;
        }
    
        /**
        生成代理类方法
        1. 类加载器,为当前类即可
        2. 代理类实现的接口
        3. 处理器接口对象
        **/
        public Object getProxy() {
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                    host.getClass().getInterfaces(), this);
        }
    
        //处理代理实例,并返回结果
        //方法在此调用
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //调用真实角色方法
            Object result = method.invoke(host, args);
            //附加方法
            seeHouse();
            contract();
            fare();
            return result;
        }
    
        //看房
        public void seeHouse() {
            System.out.println("中介带你看房");
        }
    
        //签合同
        public void contract() {
            System.out.println("租赁合同");
        }
    
        //收中介费
        public void fare() {
            System.out.println("收中介费");
        }
    }
    
    
  2. 测试类

    package demo3;
    
    public class Client {
        public static void main(String[] args) {
            //真实角色:房东
            Host host = new Host();
            //处理器接口对象
            ProxyInvocationHandler handler = new ProxyInvocationHandler();
            //设置要代理的真实角色
            handler.setHost(host);
            //动态生成代理类
            Rent proxy = (Rent) handler.getProxy();
            //调用方法
            proxy.rent();
        }
    }
    
  3. 结果
    你了解代理模式了吗??_第10张图片


好处

  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

其他好处同静态代理

你可能感兴趣的:(java,设计模式)