设计模式随笔(六):代理模式

概念:

什么是代理模式: 为其他对象提供一种代理,来控制对这个对象的访问;有些情况下一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

 

作用

1.隐藏委托类的具体实现

2.实现客户端和委托类的解耦,不改动委托类的情况下增加功能(如日志)

 

类图

以去超市买东西为例

 

 

静态代理:

预先就确定了代理和被代理对象间的关系,在编程中指编译前,代理类和被代理类的关系已经确定了;

 

/**
 * 委托类和代理类都实现了factory接口
 **/
public interface Factory {

    void sell();

    void ad();

}
public class Shop implements Factory {

    private Factory factory;

    public Shop(Factory factory) {
        this.factory = factory;
    }

    @Override
    public void sell() {
        System.out.println("商店代理销售");
        factory.sell();
    }

    @Override
    public void ad() {
        System.out.println("商店代理广告");
        factory.ad();
    }
}
public class Vendor implements Factory {
    @Override
    public void sell() {
        System.out.println("供应商销售产品");
    }

    @Override
    public void ad() {
        System.out.println("供应商打广告");
    }
}

 

public class Client {

    public static void main(String[] args) {
        // 供应商---被代理类
        Vendor vendor = new Vendor();
        // 创建供应商的代理类Shop
        Factory shop = new Shop(vendor);
        // 客户端使用时面向的是代理类Shop。
        shop.sell();

        shop.ad();

    }

}

 

动态代理:

静态代理每个代理类都必须实现代理接口,如果业务很多,会导致类迅速膨胀,为了避免这点,java基于反射提供了动态代理,实现方式常见的有两种

1.JDK提供的InvocationHandler接口和java.lang.reflect包下的Proxy类

2.cglib实现的动态代理

基于动态代理,无论业务接口和委托类如何变化,代理类都可以不变化。

 

基于InvocationHandler接口

代理类和委托对象实现同一接口

public interface User {
    void login(String userName, String pwd);
    void logout(String userName);
}

 

实现类:

public class UserImpl implements User {
    @Override
    public void login(String userName, String pwd) {
        System.out.println("用户名:" + userName + ",登录成功");
    }

    @Override
    public void logout(String userName) {
        System.out.println("用户名:" + userName + ",注销");
    }
}

 

代理类:

public class UserDynamicProxy implements InvocationHandler {

    // 代理对象
    private Object target;

    public <T> T getProxyInstance(Object target) {
        // 委托对象,真正的业务对象
        this.target = target;
        // 获取Object类的ClassLoader
        ClassLoader cl = target.getClass().getClassLoader();
        // 获取接口数组
        Class<?>[] cs = target.getClass().getInterfaces();
        // 获取代理对象并返回
        return (T) Proxy.newProxyInstance(cl, cs, this);
    }

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

        Object r = method.invoke(target, args);
        return r;
    }
}

 

测试:

public class DynamicClient {

    public static void main(String[] args) {
        // 真实角色,委托人
        User user = new UserImpl();
        // 获取委托对象user的代理对象
        UserDynamicProxy proxy = new UserDynamicProxy();

        User userProxy = proxy.getProxyInstance(user);

        userProxy.login("a1","abcd");
        userProxy.login("a2","abcd");
        userProxy.login("a3","abcd");
        userProxy.login("a4","abcd");
        userProxy.login("a5","abcd");
        userProxy.logout("a1");
    }
}

 

输出:

用户名:a1,登录成功
用户名:a2,登录成功
用户名:a3,登录成功
用户名:a4,登录成功
用户名:a5,登录成功
用户名:a1,注销

 

基于JDK有个前提条件就是“代理对象和委托对象继承同一接口”,如果没有接口怎么办呢?这时候我们可以菜用Cglib实现动态代理。

基于Cglib

委托类

public class UserClient {
    public void login(String userName, String pwd) {
        System.out.println("用户名:" + userName + ",登录成功");
    }

    public void logout(String userName) {
        System.out.println("用户名:" + userName + ",注销");
    }
}

 

代理类

public class UserClientCglibProxy implements MethodInterceptor {
    // 委托对象
    private Object target;

    public <T>T getProxyInstance(Object target) {
        this.target = target;
        // 增强类对象
        Enhancer enhancer = new Enhancer();
        // 设置其超类为target的类类型
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        Object r = proxy.invokeSuper(obj, args);
        return r;
    }
}

 

测试:

public class DynamicClient {

    public static void main(String[] args) {

        UserClient userClient = new UserClient();
        // 获取委托对象user的代理对象
        UserClientCglibProxy userClientCglibProxy = new UserClientCglibProxy();

        UserClient userProxy = userClientCglibProxy.getProxyInstance(userClient);

        userProxy.login("a1","abcd");
        userProxy.login("a2","abcd");
        userProxy.login("a3","abcd");
        userProxy.login("a4","abcd");
        userProxy.login("a5","abcd");
        userProxy.logout("a1");
    }
}

 

posted @ 2020-07-20 10:19  胡吃海喝的程序猿  阅读(159)  评论(0编辑  收藏  举报