【设计模式】代理模式-Proxy

转载:https://www.cnblogs.com/yangchongxing/p/7654725.html

代理模式定义如下:

Provide a surrogate or placeholder for another object to control access to it。为另一个对象提供一个代理或占位符以控制对它的访问。

代理模式使用非常广泛,理解代理模式对解决实际问题大有裨益的。使用代理模式必须让代理类和目标类实现相同的接口。

我们以添加用户业务为例

// 用户接口
package com.ycx.pattern.proxy;
public interface UserService {
    public void insertUser();
}
// 用户实现类
package com.ycx.pattern.proxy;
public class UserServiceImpl implements UserService {
    @Override
    public void insertUser() {
        System.out.println("添加用户...");
    }
}

我们若要添加一个用户信息,需要new一个UserServiceImpl实例对象,然后调用insertUser方法。代码如下:

// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        UserService userServie = new UserServiceImpl();
        userServie.insertUser();
    }
}

执行结果
添加用户...

静态代理

若这时新添一个业务,添加用户要在insertUser方法的开始和结束追加日志,其他地方没有这个业务,所以添加用户的业务不能修改,这种情况可以使用代理实现。代码如下:

// 代理
package com.ycx.pattern.proxy;
public class UserServiceProxy implements UserService {
    private UserService _userService;
    public UserServiceProxy(UserService userService) {
        _userService = userService;
    }
    @Override
    public void insertUser() {
        // 开始日志
        System.out.println("开始");
        _userService.insertUser();
        // 结束日志
        System.out.println("结束");
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        //  创建代理
        UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
        proxy.insertUser();
    }
}

执行结果
开始
添加用户...
结束

上边的代理是比较随便的,只要实现了用户接口,都可以,再看看使用指定代理,这样代理就必须是制定的。代码如下:

// 接口
package com.ycx.pattern.proxy;
public interface UserService {
    public void insertUser();
    public UserService getProxy();
}
// 实现类
package com.ycx.pattern.proxy;
public class UserServiceImpl implements UserService {
    private UserServiceProxy proxy = null;
    @Override
    public void insertUser() {
        // 关键代码是判断是不是自己指定的代理
        if (!isProxy()) {
            System.out.println("请使用指定的代理");
        } else {
            System.out.println("添加用户...");
        }
    }
    // 关键代码判断代理
    private boolean isProxy() {
        return this.proxy == null ? false : true;
    }
    // 关键代码返回自己的代理
    @Override
    public UserService getProxy() {
        this.proxy = new UserServiceProxy(this);
        return this.proxy;
    }
}
// 代理
package com.ycx.pattern.proxy;
public class UserServiceProxy implements UserService {
    private UserService _userService;
    public UserServiceProxy(UserService userService) {
        _userService = userService;
    }
    @Override
    public void insertUser() {
        System.out.println("开始");
        _userService.insertUser();
        System.out.println("结束");
    }
    @Override
    public UserService getProxy() {
        return this;
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Clicent {
    public static void main(String[] args) {
        // 只有使用自的代理才可以
        UserService proxy = new UserServiceImpl().getProxy();
        proxy.insertUser();
    }
}

执行结果
开始
添加用户...
结束

我们来直接new一个对象执行,或者new一个代理,验证结果。代码如下:

// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 直接new一个对象
        new UserServiceImpl().insertUser();
    }
}

执行结果
请使用制定的代理

// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 直接new一个代理
        UserServiceProxy proxy = new UserServiceProxy(new UserServiceImpl());
        proxy.insertUser();
    }
}

执行结果
开始
请使用制定的代理
结束

从上面看都是不行的,只能使用指定的代理才可以。

下面是重头戏

动态代理-即面向横切面编程AOP(Aspect Oriented Programming)
InvocationHandler 是JDK提供的动态代理接口。Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

还是上面的例子,用动态代理实现代码如下:

// 动态代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object object;
    MyInvocationHandler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始");
        Object result = method.invoke(object, args);
        System.out.println("结束");
        return result;
    }
}
// 客户端
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
    public static void main(String[] args) {
        InvocationHandler h = new MyInvocationHandler(new UserServiceImpl());
        // 使用Proxy获得实例
        UserService proxy = (UserService) Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, h);
        proxy.insertUser();
    }
}

上面的实现方式客户端使用起来不方便,可以定义一个专门的客户代理。代码如下:

// 动态代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
    private Object object;
    MyInvocationHandler(Object object) {
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始");
        Object result = method.invoke(object, args);
        System.out.println("结束");
        return result;
    }
}
// 客户代理
package com.ycx.pattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DynamicProxy {
    @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(T instance) {
        ClassLoader loader = instance.getClass().getClassLoader();
        Class<?>[] interfaces = instance.getClass().getInterfaces();
        InvocationHandler h = new MyInvocationHandler(instance);
        return (T) Proxy.newProxyInstance(loader, interfaces, h);
    }
}
// 客户端
package com.ycx.pattern.proxy;
public class Client {
    public static void main(String[] args) {
        // 使用定制的代理返回实例
        UserService proxy = DynamicProxy.newProxyInstance(new UserServiceImpl());
        proxy.insertUser();
    }
}

 待续...

原文地址:https://www.cnblogs.com/yangchongxing/p/7654725.html