【设计模式】结构型01代理模式(Proxy Pattern)
代理模式(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)的更多相关文章
- python设计模式---结构型之代理模式
主要想着nginx:) from abc import ABCMeta, abstractmethod # 结构型设计模式---代理模式 class Actor: def __init__(self) ...
- 【转】设计模式(十一)代理模式Proxy(结构型)
设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...
- 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)
原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...
- 二十四种设计模式:代理模式(Proxy Pattern)
代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...
- 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释
代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...
- 代理模式(Proxy pattern)
代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...
- JAVA设计模式 5【结构型】代理模式的理解与使用
今天要开始我们结构型 设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西. 结构型设计模式 结构型设计模式又分为 类 结构型 对象 结构型 前 ...
- 设计模式——代理模式(Proxy Pattern)
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...
随机推荐
- Entity Framework加载数据的三种方式。
MSDN文章Loading Related Entities 有 Eagerly Loading Lazy Loading Explicitly Loading 三种方式. 而看到查询中包含Inclu ...
- 6 Wcf使用Stream传输
1.创建service和client项目 service项目新建wcf服务文件 MediaService 和 IMediaService IMediaService 代码为 using System. ...
- JDBC 使用这个是MySQL下的
import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.R ...
- 从 XML 到 XPath
XPath是 W3C(World Wide Website Consortium) 的一个标准.它最主要的目的是为了在 XML1.0 或 XML1.1 文档节点树中定位节点所设计. XPath 即为 ...
- Codeforces #264 (Div. 2) D. Gargari and Permutations
Gargari got bored to play with the bishops and now, after solving the problem about them, he is tryi ...
- 运行该脚本出现/bin/sh^M: bad interpreter: No such file or directory
错误中脚本文件的一个非常可能的原因是DOS格的, 即每一行的行尾以\r\n来标识, 其ASCII码各自是0x0D, 0x0A. 能够有非常多种办法看这个文件是DOS格式的还是UNIX格式的, 还是M ...
- js仿黑客帝国文字数字雨效果
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- WPF UpdateSourceTrigger的使用
<Window x:Class="XamlTest.Window8" xmlns="http://schemas.microsoft.com/winf ...
- MFC应用程序配置不正确解决方案(manifest对依赖的强文件名,WinSxs是windows XP以上版本提供的非托管并行缓存)
[现象] 对这个问题的研究是起源于这么一个现象:当你用VC++2005(或者其它.NET)写程序后,在自己的计算机上能毫无问题地运行,但是当把此exe文件拷贝到别人电脑上时,便不能运行了,大致的错误提 ...
- Apache Cordova开发环境搭建(一)-Visual Studio
原文:Apache Cordova开发环境搭建(一)-Visual Studio 一.使用Visual Studio开发Apache Cordova手机App 1.版本要求,Visual Studio ...