代理模式(Proxy Pattern)


定义:顾名思义,增加中间层,为其他对象提供一种代理以控制对这个对象的访问。核心在于代理二字。

1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。

2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

静态代理与动态代理:

静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理类:在程序运行时,运用反射机制动态创建而成。
静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。

动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。

代码:静态代理:

这里笔者通过一个替考的例子,演示了小学生王小虎找人替考被骗子骗的故事:

package com.pat.proxy.staticproxy;
/**
* 统一接口
* @author ZX
*
*/
public interface Student {
void exam();
}
/**
* 被代理类-学生王小虎
* @author ZX
*
*/
class BadStudent implements Student{
private String name="王小虎"; @Override
public void exam() {
System.out.println(name+"参加考试"); }
public BadStudent(){
}
public BadStudent(String name){
this.name=name;
}
}
/**
* 代理类-替考的骗子
* 静态代理只代理固定的类
* @author ZX
*
*/
class Swindler implements Student{
private String name;
private BadStudent badStudent; @Override
public void exam() {
//非重点,前后可以添加某些操作
System.out.println(name+"进入考场");
badStudent= new BadStudent(name);
badStudent.exam();
System.out.println(name+"没交试卷"); }
public Swindler(String name){
this.name=name;
}
}

测试类:

package com.pat.proxy.staticproxy;

public class Test {
public static void main(String[] args) {
Student s = new Swindler("老司机");
s.exam();
}
}

结果:

老司机进入考场
老司机参加考试
老司机没交试卷

这就说明了一个问题,做生意得讲诚信,你好好搞替考业务,发展起来说不定还能开个连锁。这样子做生意是不会走的长远的!但是考虑到这个替考人没上过小学,也只能怪小虎人品不好了。

代码:动态代理:

以下是动态代理的演示,采用了JDK提供的工具,省了几十行代码:

package com.pat.proxy;
/**
* 本类中
*/ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; /**
* 被代理类接口
*/
public interface People {
public int getNum() ;
} /**
* 被代理类实现类
*/
class Peopleimpl implements People{
private int num=100; public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
}
}
/**
*代理类,需要实现InvocationHandler接口
*/
class MyInv implements InvocationHandler{
//被代理对象
Object obj; public MyInv(Object obj){
this.obj=obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
return result;
}
}

测试类:

package com.pat.proxy;

import java.lang.reflect.Proxy;
import java.util.Objects; /**
* 测试类:
* 补充,非空判断这么用比较装逼:
* People p2=null;
* Objects.requireNonNull(p2,"第二个对象不能为空");
*/
public class Test2 {
public static void main(String[] args) {
//动态代理有JDK和CGLIB两种工具,cglib是更底层的写法,所以效率会高一些
People p = new Peopleimpl();
//真正的代理者。
MyInv my = new MyInv(p);
//第一个参数是类加载器,第二个参数是这个代理者实现哪些接口(与被代理者实现的是相同的接口)
People pp= (People)Proxy.newProxyInstance(p.getClass().getClassLoader(),p.getClass().getInterfaces(),my);
System.out.println(pp.getNum()); }
}

结果:

100

动态代理JDK中的实现:

每日手记:
2018年5月15日11:16:07
Returns an instance of a proxy class for the specified interfaces
返回一个指定接口的代理实例
that dispatches method invocations to the specified invocation
handler.
将方法调用分派到指定的处理程序 /**
//糊上注释是为了看一下老外是怎么写注释的,即使看不懂全部,也可以对比自己的注释参考一下,其实注释写得多也给人感觉很牛逼
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to {@code getProxyClass}
* are violated
* @throws SecurityException if a security manager, <em>s</em>, is present
* and any of the following conditions is met:
* <ul>
* <li> the given {@code loader} is {@code null} and
* the caller's class loader is not {@code null} and the
* invocation of {@link SecurityManager#checkPermission
* s.checkPermission} with
* {@code RuntimePermission("getClassLoader")} permission
* denies access;</li>
* <li> for each proxy interface, {@code intf},
* the caller's class loader is not the same as or an
* ancestor of the class loader for {@code intf} and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to {@code intf};</li>
* <li> any of the given proxy interfaces is non-public and the
* caller class is not in the same {@linkplain Package runtime package}
* as the non-public interface and the invocation of
* {@link SecurityManager#checkPermission s.checkPermission} with
* {@code ReflectPermission("newProxyInPackage.{package name}")}
* permission denies access.</li>
* </ul>
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
        //克隆了接口参数
final Class<?>[] intfs = interfaces.clone();
//安全管理器,有关权限以及安全的东西,无视之
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
//下面就是通过反射创建动态代理对象的过程了: /*
* Look up or generate the designated proxy class.查找或生成指定的代理类。
//如果由给定的加载器定义的代理类。
//给定的接口存在,这将简单地返回缓存的副本(这个缓存取自哪里?猜想:类加载???);
//否则,它将通过ProxyClassFactory创建代理类。
//如果没有接口参数intfs,则会抛出空指针
*/
Class<?> cl = getProxyClass0(loader, intfs); /*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取构造方法
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {//非公有方法处理
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//返回创建的代理对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}

【设计模式】结构型01代理模式(Proxy Pattern)的更多相关文章

  1. python设计模式---结构型之代理模式

    主要想着nginx:) from abc import ABCMeta, abstractmethod # 结构型设计模式---代理模式 class Actor: def __init__(self) ...

  2. 【转】设计模式(十一)代理模式Proxy(结构型)

    设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...

  3. 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  4. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  5. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  6. 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释

    代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...

  7. 代理模式(Proxy pattern)

    代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...

  8. JAVA设计模式 5【结构型】代理模式的理解与使用

    今天要开始我们结构型 设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西. 结构型设计模式 结构型设计模式又分为 类 结构型 对象 结构型 前 ...

  9. 设计模式——代理模式(Proxy Pattern)

    代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...

随机推荐

  1. Oracle 学习笔记 18 -- 存储函数和存储过程(PL/SQL子程序)

    PL/SQL子程序 它包含了函数和过程.此功能是指用户定义的函数.和系统功能是不同的.子程序通常完成特定的功能PL/SQL座.,能够被不同的应用程序多次调用.Oracle提供能够把PL/SQL程序存储 ...

  2. PHP正则表达式入门教程[转]

      思维导图 点击下图,可以看具体内容!     介绍          正则表达式,大家在开发中应该是经常用到,现在很多开发语言都有正则表达式的应用,比如javascript,java,.net,p ...

  3. 机器学习: TensorFlow with MLP 笑脸识别

    Tensor Flow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库.节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数 ...

  4. 使用 matlab 数据集的生成(generate datasets)

    一般手工生成的数据集(artificial datasets),通常用于实验部分最开始的演示和示意,用于对结果的一种精确计算和量化分析. 1. Swiss/Helix/Twinpeaks/Broken ...

  5. ASP.NET Core macOS 环境配置 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core macOS 环境配置 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 是对 ASP.NET 有重大意义的一次重新设计.本章节我 ...

  6. Hibernate_12_HQL句子

    使用HQL查询功能: (1)与SQL相似,SQL用. (2)SQL查询的是表和表中的列.HQL查询的是对象与对象中的属 (3)HQL的keyword不区分大写和小写,类名与属性名是区分大写和小写 (4 ...

  7. 入骨三分的“我们是谁”IT行业版

    这组漫画用简单的台词.粗犷的线条,把很多人心中对甲方(客户)的不满彻底地发泄了一通,并且出现了很多变种版本,引发了传播热潮. http://news.sina.com.cn/c/nd/2017-08- ...

  8. jquery trim()的用法

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  9. PostSharp-5.0.26安装包_KeyGen发布_支持VS2017

    PostSharp-5.0.26安装包_KeyGen发布_支持VS2017 请低调使用. PostSharp安装及注册步骤截图.rar 请把浏览器主页设置为以下地址支持本人.https://www.d ...

  10. Win10《芒果TV》更新v3.8.50勇敢版:新增短信和扫码登录

    勇敢,是心中最初的信仰,实景科幻实验节目<勇敢的世界>,重装上阵对抗升级,<中餐厅2>皇阿玛圣驾亲临,坐镇中国味道.Win10版<芒果TV>全平台同步更新勇敢版v3 ...