设计模式-代理模式

代理(Proxy)是一种设计模式,提供了间接对目标对象进行访问的方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的功能上,增加额外的功能补充,即扩展目标对象的功能.

代理模式

一、简单介绍

1、优点:符合了设计模式的开闭原则,即在对既有代码不改动的情况下进行功能的扩展。
2、常见分类
  • 静态代理
  • 动态代理

二、静态代理

定义一个接口IUserDao,save()方法模拟动作,目标对象UserDao实现这个接口,如果事静态模式需要代理对象也实现这个接口,调用的时候通过调用代理对象的方法来调用目标对象

1、定义接口
public interface UserService {

    void save();
}
2、目标对象
public class UserServiceImpl implements UserService {
    @Override
    public void save() {
        System.out.println("保存用户");
    }
}
3、代理对象
public class UserServiceProxy implements UserService {

    private UserService userService;

    public  UserServiceProxy(UserService userService){
        this.userService=userService;
    }

    @Override
    public void save() {
        System.out.println("保存用户之前");
        userService.save();
        System.out.println("保存用户之后");

    }
}
4、测试类
public static void main(String[] args) {
        UserService userService=new UserServiceImpl();
        UserServiceProxy userServiceProxy=new UserServiceProxy(userService);
        userServiceProxy.save();
    }
5、结果

20200110105306

6、静态代理总结
  • 优点:可以在不修改原有对象的功能上,对目标功能进行扩展;
  • 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护;
    如果要避免这个缺点就要使用动态代理。

三、动态代理

1) JDK动态代理

JDK动态代理不需要代理对象实现接口,但是目标对象必须实现接口,代理对象是通过JDK的API在内存中构建代理对象(在java.lang.reflect.Proxy包下)

1、这里我们只需要写代理类
public class JdkUserServiceProxy implements InvocationHandler {

    private Object target;

    public  JdkUserServiceProxy(Object target){
        this.target=target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("之前");
        Object result = method.invoke(target, args);
        System.out.println("之后");
        return result;
    }


    // 生成代理类
    public Object CreatProxyedObj(){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

}
2、测试
public static void main(String[] args) {
        JdkUserServiceProxy jdkUserServiceProxy=new JdkUserServiceProxy(new UserServiceImpl());
        UserService userService = (UserService)jdkUserServiceProxy.CreatProxyedObj();
        userService.save();
    }
3、结果

20200110134032

4、特点

JDK动态代理是在内存中动态生成一个对象,代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。

2)cglib动态代理

上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做Cglib代理.

1、编写业务代码
public class UserDao {
    public void save() {
        System.out.println("保存用户");
    }

}
2、重新代理类,这里只需要实现MethodInterceptor
public class CglibUserServiceProxy implements MethodInterceptor {

    private Object target;

    public CglibUserServiceProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("开始执行保存前...");
        Object result = method.invoke(target, objects);
        System.out.println("保存后...");
        return result;
    }

    public Object getProxyInstance() {
        // 工具类
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);

        return enhancer.create();
    }
}
3、测试
 public static void main(String[] args) {
        CglibUserServiceProxy cglibUserServiceProxy = new CglibUserServiceProxy(new UserDao());
        UserDao userDao = (UserDao)cglibUserServiceProxy.getProxyInstance();
        userDao.save();
    }
3)动态代理总结:

如果目标对象有实现接口,用JDK代理.
如果目标对象没有实现接口,用Cglib代理.

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.fengpt.cn/archives/设计模式-代理模式还没写完