设计模式——个人学习之代理模式

代理模式

介绍

代理模式的定义:通过一些代理对象来控制访问目标对象,访问者不会直接访问目标对象,而是通过代理类来进行访问,代理类是访问者和目标对象之间的桥梁。

在我们生活中,比如我们要去买房子,我们不可能直接去看房子,必须要通过房地产经销商来推荐和介绍,我们才能买到理想中的房子,在这个例子里,房地产经销商就是类似一个代理类,房子就是目标类,而我们买房子的人就是访问类。类似的例子还有很多,比如各种产品的代理商等等

代理模式的主要角色如下。

  1. 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  2. 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  3. 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

静态代理

静态代理很简单,我们只需要在目标类外面嵌套一个类,将这个类暴露给外面的访问者就可以了,代码如下:

接口:

package com.example.demo.design.proxy.stat;

/**
 * 定义业务方法接口
 */
public interface Role {
    public void getGift();
}

目标类:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:02
 * @description: 具体业务实现类
 */
public class Celebrity implements Role{
    @Override
    public void getGift() {
        System.out.println("获得礼物了!");
    }
}

代理类:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:03
 * @description: 代理类
 */
public class RoleProxy {
    private Role role;

    public RoleProxy(Role role) {
        this.role = role;
    }

    public void getGift(){
        System.out.println("代理开始");
        role.getGift();
        System.out.println("代理结束");
    }
}

测试:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:05
 * @description: 测试类
 */
public class TestProxy {
    public static void main(String[] args) {
        RoleProxy roleProxy = new RoleProxy(new Celebrity());
        roleProxy.getGift();
    }
}

结果:
    代理开始
	获得礼物了!
	代理结束

如果有多个代理类嵌套,可以通过下面的方式:

代理类1:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:03
 * @description: 代理类
 */
public class RoleProxy implements Role{
    private Role role;

    public RoleProxy(Role role) {
        this.role = role;
    }

    public void getGift(){
        System.out.println("代理开始");
        role.getGift();
        System.out.println("代理结束");
    }
}

代理类2:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:48
 * @description: 代理类
 */
public class RoleMethodProxy implements Role{
    private Role role;

    public RoleMethodProxy(Role role) {
        this.role = role;
    }
    @Override
    public void getGift() {
        System.out.println("新的代理开始");
        role.getGift();
        System.out.println("新的代理结束");
    }
}

测试类:

package com.example.demo.design.proxy.stat;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:05
 * @description: 测试类
 */
public class TestProxy {
    public static void main(String[] args) {
        RoleProxy roleProxy = new RoleProxy(new Celebrity());
        RoleMethodProxy roleMethodProxy = new RoleMethodProxy(roleProxy);
        roleMethodProxy.getGift();
    }
}

结果:
    新的代理开始
	代理开始
	获得礼物了!
	代理结束
	新的代理结束

个人觉得,静态代理在实际运用中可能会很少出现,因为它有个很明显的弊端,不可能在每个业务目标类外面都嵌套个代理类,这样代码会非常的冗余,同时,如果目标类发生改变,那么代理类也需要做相应的修改,显然这不是一个很好的方法。

动态代理

使用动态代理,我们不需要在项目开发过程中自己手动创建代理类,而是由JDK在运行的时候为我们动态的来创建,这里是通过动态处理类来生成代理类。需要使用到InvocationHandler以及Proxy类的newProxyInstance方法

接口:

package com.example.demo.design.proxy.dynamic;

/**
 * 定义业务方法接口
 */
public interface Role {
    public void getGift();

    public void getLife();
}

目标类:

package com.example.demo.design.proxy.dynamic;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:02
 * @description: 具体业务实现类
 */
public class Celebrity implements Role {
    @Override
    public void getGift() {
        System.out.println("获得礼物了!");
    }

    @Override
    public void getLife() {
        System.out.println("获得life!");
    }
}

动态代理类:

package com.example.demo.design.proxy.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:19
 * @description: 动态代理类
 */
public class ProxyHandler implements InvocationHandler {

    private Object targetObj;

    public Object newProxyInstance(Object targetObj) {
        this.targetObj = targetObj;

        return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),
                targetObj.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("代理开始");
        Object obj = method.invoke(targetObj,args);
        System.out.println("代理结束");
        return obj;
    }
}

测试类:

package com.example.demo.design.proxy.dynamic;


/**
 * @author: sunzhinan
 * @create: 2020-08-08 19:43
 * @description: 测试类
 */
public class TestProxy {
    public static void main(String[] args) {
        ProxyHandler handler = new ProxyHandler();
        Role role = (Role) handler.newProxyInstance(new Celebrity());
        role.getGift();
        System.out.println("------------");
        role.getLife();

    }
}

结果:
    代理开始
	获得礼物了!
	代理结束
    ------------
    代理开始
    获得life!
    代理结束

与静态代理比较,动态代理不需要对目标类中的每个方法进行重复的代理,可以统一处理,所以动态代理的应用会使我们的代码更加简单,复用性强。

Cglib代理

Cglib代理需要额外引入一个jar包,但是如果你项目使用的Spring,那么就可以直接使用,因为Spring的AOP也有的是基于Cglib代理(JDK动态代理与CGLib动态代理均是实现Spring AOP的基础)。那么动态代理和Cglib代理的区别就是,动态代理需要目标类通过接口定义业务方法,对于没有接口的类,那该如何代理呢,而Cglib可以解决没有实现接口类的代理。但Cglib采用的是继承,所以不能对final修饰的类进行代理。

接口:

package com.example.demo.design.proxy.cglib;

/**
 * 定义业务方法接口
 */
public interface Role {
    public void getGift();

    public void getLife();
}

目标类:

package com.example.demo.design.proxy.cglib;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 18:02
 * @description: 具体业务实现类
 */
public class Celebrity implements Role {
    @Override
    public void getGift() {
        System.out.println("获得礼物了!");
    }

    @Override
    public void getLife() {
        System.out.println("获得life!");
    }
}

Cglib代理类

package com.example.demo.design.proxy.cglib;

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 21:45
 * @description: 代理类
 */
public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理开始!");
        Object object = methodProxy.invokeSuper(o,objects);
        System.out.println("代理结束!");
        return object;
    }
}

测试类:

package com.example.demo.design.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;

/**
 * @author: sunzhinan
 * @create: 2020-08-08 21:43
 * @description: 测试类
 */
public class TestProxy {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Celebrity.class);
        enhancer.setCallback(new MyMethodInterceptor());

        Celebrity celebrity = (Celebrity) enhancer.create();
        celebrity.getGift();
        System.out.println("-------------");
        celebrity.getLife();
    }
}

结果:
    代理开始!
    获得礼物了!
    代理结束!
    -------------
    代理开始!
    获得life!
    代理结束!
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页