先来看看几个场景,比如刷网课,我们都要自己刷对吧,一节节看,还有单元测试啥的,浪费时间又学不到自己感兴趣的东西,或者玩游戏,需要升级,但是又常常充满罪恶感,可惜自己没有好好学习。那我们用代码表示一下就是这样子。
一个抽象主题接口,用来定义我们要做的事情的一个抽象接口:

package com.ongbo.ProxyPattern;/*** 抽象主题接口角色* */
public interface SubObject {/*** 正常代理的请求方法*/public void request();/*** 本篇博客用例使用的代理方法* 平常开发不需要* */public void login(String user,String password);public void kill();public void upgrade();
}

真实主题类,用来实现抽象主题的具体操作类

package com.ongbo.ProxyPattern;/*** 真实主题* 需要实现抽象主题接口* */
public class RealSubObject implements SubObject{//保存用户名private String name = "";public RealSubObject(String name){this.name = name;}public void request() {}public void login(String user, String password) {System.out.println("用户"+user+"的用户"+this.name+"登陆了");}public void kill() {System.out.println(this.name+"杀了一个怪物");}public void upgrade() {System.out.println(this.name+"升级了");}
}

Client类,代表我自己去操作:

package com.ongbo.ProxyPattern;public class Client_demo1 {public static void main(String[] args) {SubObject gameuser = new RealSubObject("ongbo");gameuser.login("xxxx","xxxxx");gameuser.kill();gameuser.upgrade();}
}

这上面就是一个游戏,自己作死的打,但是就是菜,打不上去,没有成就感,还耽误了自己的学习。这时候可能就会像干脆让别人代替我玩算啦。这时候就有了代理模式
代理模式即委托,代理,就是相让别人代替我做一件事情,我似乎只要发一种指令,来减少我和那件事情的耦合,比如,我们在学校有网课,可以花钱给别人代刷网课,或者你玩游戏很菜,于是让别人玩自己的号码来提神等级这些都是代理模式的一种体现。

代理模式中的角色

SubObjec抽象主题角色

声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以使用代理主题,而Client常常需要根据抽象主题进行编程

Proxy代理主题角色

它包含了对真实主题的引用,从而可以在任何时候操作真实主题 对象;在代理主题角色中提供一个与真实主题角色相同的接口,以便在任何时候都可以替代 真实主题;代理主题角色还可以控制对真实主题的使用,负责在需要的时候创建和删除真实 主题对象,并对真实主题对象的使用加以约束。通常,在代理主题角色中,客户端在调用所 引用的真实主题操作之前或之后还需要执行其他操作,而不仅仅是单纯调用真实主题对象中 的操作。

RealObject真实主题

它定义了代理角色所代表的真实对象,在真实主题角色中 实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操 作。


代理模式简单实现

抽象主题
package com.ongbo.ProxyPattern;/*** 抽象主题接口角色* */
public interface SubObject {/*** 正常代理的请求方法*/public void request();/*** 本篇博客用例使用的代理方法* 平常开发不需要* */public void login(String user,String password);public void kill();public void upgrade();
}
代理主题角色
package com.ongbo.ProxyPattern;
/*** 代理主题角色* */
public class ObjectProxy implements SubObject {/** 保存一个真实主题角色,在构造方法传入关联真实主题角色*/private SubObject subObject = null;public ObjectProxy(SubObject subObject){this.subObject = subObject;}/** 下面就用上面关联的真实主题角色对象来操控访问 */public void request() {}public void login(String user, String password) {this.subObject.login(user,password);}public void kill() {this.subObject.kill();}public void upgrade() {this.subObject.upgrade();}
}
真实主题角色
package com.ongbo.ProxyPattern;/*** 真实主题* 需要实现抽象主题接口* */
public class RealSubObject implements SubObject{//保存用户名private String name = "";public RealSubObject(String name){this.name = name;}public void request() {}public void login(String user, String password) {System.out.println("用户"+user+"的用户"+this.name+"登陆了");}public void kill() {System.out.println(this.name+"杀了一个怪物");}public void upgrade() {System.out.println(this.name+"升级了");}
}
Client实现
package com.ongbo.ProxyPattern;public class Client_demo2 {public static void main(String[] args) {//定义一个游戏上瘾的玩家,或者一个爱学习的但是要刷客的学生,即真实主题对象SubObject realObject = new RealSubObject("ongbo");//然后创建一个代理主题对象,并且将其与真实主题对象相关联SubObject ProxyObject = new ObjectProxy(realObject);/**接下来全部使用代理主题对象去操作*/ProxyObject.login("xxxx","xxx");ProxyObject.kill();ProxyObject.upgrade();}
}

好了,到现在为止,至少已经有人替你干活了,你就不用自己去沉迷游戏,或者还要一边学习,一边刷网课,这样就可以减轻自己的负担,让自己去做其他事情,而且不用那么多复杂的逻辑了。

上面代码看到了,在看到Client的时候,你会看见,不还是要在本地弄一个真实主题对象吗,我Client不还是要管理这个对象吗,这时候就可以修改一下,在真实主题内关联抽象主题,来看看自己创建没有,而我们把真是主题角色的创建推移到代理主题的构造方法,在Client上就只要传入一个name即可,而不用先创建一个真实主题对象再传入
Client改动

//原版
SubObject ProxyObject = new ObjectProxy(realObject);
/** 现版*/
SubObject ProxyObject = new ObjectProxy("ongbo");
//原版
public ObjectProxy(SubObject subObject){this.subObject = subObject;        }
//现版public ObjectProxy(String name){SubObject realObject = new RealSubObject(name);this.subObject = realObject;}

而在真实主题角色中,也可以自己关联代理主题角色
这样子,我们就可以将真实主题和Client屏蔽了,Client不用管真是主体的实际是谁,只知道名字,也不需要进行更复杂的操作

动态代理

有动态代理就有静态代理,上面的都是静态代理,即都要使用具体的Proxy类去实现抽象主题接口,从而才能够使Client间接使用真实主题。但是静态代理有缺点的,就是对于每个逻辑,可能都要去实现一个代理类,从而导致类爆炸,而动态代理就回去解决这个问题

package com.ongbo.ProxyPattern;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class Client_demo3 {public static void main(String[] args) {/**创建一个真是主题对象*/SubObject realObject = new RealSubObject("ongbo");/**使用JDK中的InvocationHandler,去实现这个接口,实现类NormalHandler*/InvocationHandler invocationHandler = new NormalHandler(realObject);/**获得真实主题类的ClassLoader*/ClassLoader cl = realObject.getClass().getClassLoader();/**使用Proxy.newProxyInstance去构建一个抽象主题的代理*//**参数说明:* 第一个参数:ClassLoader,即我们真实主题对象的ClassLoader就行* 第二个参数:我们真实主题类实现的接口* 第三个参数:我们上面实现的InvocationHandler* */SubObject newProxyInstance = (SubObject)Proxy.newProxyInstance(cl, realObject.getClass().getInterfaces(), invocationHandler);/**调用相应的方法即可*/newProxyInstance.login("xx","xxx");newProxyInstance.kill();newProxyInstance.upgrade();}
}

那来看看那个InvocationHandler的实现类NormalHandler

package com.ongbo.ProxyPattern;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class NormalHandler implements InvocationHandler {/**这里是自己写的逻辑而已,引入的是真实主题的关联*/private Object obj = null;Class cls = null;public NormalHandler(Object obj){this.obj = obj;}/**这是实现Invocationhandler必须实现的方法* 可以看到里面使用了反射,来调用方法了。* */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = method.invoke(this.obj,args);return result;}
}

Proxy类源码解析

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{//检查这个Handler是不是null,会抛出NullPointExeceptionObjects.requireNonNull(h);//克隆我们要生成代理类的所有接口,即这个接口数组final Class<?>[] intfs = interfaces.clone();//检查权限final SecurityManager sm = System.getSecurityManager();if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** 查找或者生成一个特定的代理类对象*/Class<?> cl = getProxyClass0(loader, intfs);/** 检查权限,并且调用这个代理类的参数为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);}}/*** 生成一个代理类,生成之前必须检查权限*/private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}//如果这个类加载已经实现了这个接口的代理类,那么就会返回这个缓存,否则就直接通过ProxyClassFactory工厂类创建这个对象return proxyClassCache.get(loader, interfaces);}

设计模式怎么玩-代理模式相关推荐

  1. 设计模式学习之代理模式学习(一)

    设计模式学习之代理模式学习(一) 关于设计模式想必学习过Java语言的人都知道吧,当时对其进行深入学习的的人应该不是很多.在我看来设计方面的知识相比于框架应用配置等知识要有意思的多,并且设计模式的对一 ...

  2. 设计模式之静态代理模式实战

    转载自 设计模式之静态代理模式实战 静态代理模式很简单,代理类和实现类都实现相同的接口,然后通过代理类来调用实现类的方法. 如我们想保存用户信息之前打印用户信息,或者保存用户信息之后把这些信息缓存下来 ...

  3. 设计模式之蝉——代理模式上中

    代理模式的扩展 1 普通代理 :这种代理就是客户端只能访问代理角色,而不能访问真实角色.与设计模式之蝉--代理模式上 片基本差不多. (1)Subject抽象主题角色: (2)RealSubject具 ...

  4. 每日一个设计模式之【代理模式】

    文章目录 每日一个设计模式之[代理模式] ☁️前言

  5. 【C++设计模式】-03代理模式

    代理模式 代理模式介绍 今天继续学习设计模式,今天我们来学习代理模式.其实这个模式呢在我们的生活早已经运用起来了.笔者看到这个模式就联想到了代理商.我们客户买东西一般都是经过代理商的,代理商和真正的生 ...

  6. 大话设计模式C++版——代理模式

        本篇開始前先发个福利,程杰的<大话设计模式>一书高清电子版(带文件夹)已上传至CSDN,免积分下载. 下载地址:http://download.csdn.net/detail/gu ...

  7. Java24种设计模式(第二种)--代理模式(Proxy Pattern)

    Java24种设计模式 (第二种) 一.代理模式(Proxy Pattern) 模式逻辑: 什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道 被代理人能做哪些事 ...

  8. 23种java设计模式详解-代理模式

    什么是代理模式: Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问.所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类, ...

  9. 设计模式:4.代理模式

    代理模式 代理模式属于结构型模式 定义:为其他对象提供一种代理以控制对这个对象的访问 代理模式就是在操作原对象的时候,多出来一个代理类,用来对原对象的访问进行控制和替代原对象进行一些操作 模式类图 角 ...

最新文章

  1. 看一下基于ASP.NET MVC的开源社区项目Orchard
  2. linux网络配置练习
  3. Android数据库新王者-Realm入门教程
  4. 解决MariaDB无法远程连接
  5. SQL反模式笔记7——多列属性
  6. qmoc文件_Qt中Q_OBJECT与生成的moc文件的作用
  7. 【Error】Provider com.sun.xml.stream.ZephyrParserFactory not found
  8. SAP Spartacus autofocus Directive的失败的单元测试 - 2021年1月13日 1.1
  9. Card Game Again CodeForces - 818E (双指针)
  10. android垂直排列元素_元素的视图属性之client
  11. Oracle用户密码过期的处理方法
  12. hive collect_set mysql group_concat
  13. 数字一阶低通滤波器立体解析
  14. leapFTP 使用笔记
  15. IDEA展示隐藏文件夹
  16. 工程伦理第四章习题答案
  17. 关于中部城市人才外流问题的思考
  18. Arduino与Proteus仿真实例-MPX4250压力传感器驱动仿真
  19. 云帆加速:广电新媒体营收如何跑赢成本
  20. T6客户档案-供应商-存货名称不能录入空格--sql 怎么去掉最后一个字符

热门文章

  1. mysql connection is read-only._Connection is read-only问题的产生原因与解决方法
  2. TPA_LSTM项目代码解读-pyrtoch
  3. RibbonGroup
  4. Java mybatis try catch 捕获sql主键重复异常
  5. 用图表说话,说服他人真的很简单
  6. 百无聊赖之JavaEE从入门到放弃(五)this的本质_对象创建过程的4 步_隐式参数 static
  7. 用python画小花_用python的小海龟 Turtle 画一朵好看又有趣的小花-Go语言中文社区...
  8. Netty学习(一)-- Netty 底层 Java NIO
  9. python中date用法_Python教程--date 对象用法
  10. 领英个人简介如何支持html,专业人士:如何在领英上展示自我