转载: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();
}
}

待续...

最新文章

  1. 好文推荐系列---------JS模板引擎
  2. document.querySelector和querySelectorAll方法
  3. Bit data type
  4. topcoder算法练习3
  5. 使用java连接hive,并执行hive语句详解
  6. js 常用正则表达式(不断维护中)
  7. admin
  8. 【长期更新】迈向现代化的 .Net 配置指北
  9. php操作Memcache的一个类库
  10. 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型及原型设计
  11. [20190306]共享服务模式与SDU.txt
  12. CSS中border和outline的区别
  13. SecureCR 改变背景色和文字颜色
  14. Windows句柄数限制
  15. Linux Kafka集群管理工具kafka-manager的安装使用
  16. ansible中常用模块详解
  17. js 数组去重的几种方式及原理
  18. HDU 1260:Tickets(DP)
  19. 浅谈tcp socket的backlog参数
  20. Magical Girl Haze 南京网络赛2018

热门文章

  1. python:类2——有关类和对象的BIF内置函数
  2. Ubuntu Server16.04 安装Odoo11
  3. 阅读《Windows 黑客编程技术详解》(甘迪文著)【正在进行】
  4. 快速搭建 SpringCloud 微服务开发环境的脚手架
  5. mysql锁简谈
  6. LoadRunner中的90%响应时间
  7. Netty Pipeline与ChannelHandler那些事
  8. 解密面试中的套路,你都get到了么?
  9. C语言之修改常量
  10. Dockerfile构建私有镜像