代理模式(Proxy)
17.11.1 代码模式的基本介绍
1) 代理模式: 为一个对象提供一个替身,以控制对这个对象的访问
2) 被代理的对象可以是 远程对象、 创建开销大的对象或需要 安全控制的对象(动态代理)
3) 代理模式有不同的形式(比如 远程代理,静态代理,动态代理),都是为了控制与管理对象访问

看一个项目需求
糖果机项目,具体要求如下:
1) 某公司需要将销售糖果的糖果机放置到本地( 本地监控)和外地( 远程监控),进行糖果销售。
2) 给糖果机插入硬币,转动手柄,这样就可以购买糖果。
3) 可以监控糖果机的状态和销售情况。

完成监控远程糖果机
说明:对远程糖果机的状态和销售情况进行监控,相对麻烦些,我们先分析一下
1) 方式 1:因为远程糖果机不在本地,比如在另外的城市,国家,这时可以使用 socket  编程来进
行网络编程控制(缺点:麻烦)
2) 方案 2:在远程放置 web 服务器,通过 web 编程来实现远程监控。
3) 方案 3:使用 RMI(Remote Method Invocation) 远程方法调用来完成对远程糖果机的监控,因为
RMI 将 socket 的底层封装起来,对外提供调用方法接口即可,这样比较简单,这样我们就可以实现远
程代理模式开发。

Java RMI 实现远程代理
RMI 指的是远程方法调用 (Remote Method Invocation)。它是一种 机制,能够让在个 某个 Java  虚拟
个 机上的对象调用另一个 Java  虚拟机中的对象上的方法。可以用此方法调用的任何对象必须实现该远
程接口,RMI 可以将底层的 socket 编程封装,简化操作。(如图)

Java RMI 的介绍
1) RMI 远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制。
2) 使用 RMI 机制,一台计算机上的对象可以调用另外 一台计算机上的对象来获取远程数据。
3) RMI 被设计成一种 面向对象开发方式,允许程序员使用远程对象来实现通信

RMI简单案例

开启一个服务

import java.rmi.{Remote, RemoteException}//这是一个接口文件.该文件会给远程端和本地端是使用
trait MyRemote extends Remote{//一个抽象方法@throws(classOf[RemoteException])def sayHello(): String //throws RemoteException}

import java.rmi.registry.LocateRegistry
import java.rmi.{Naming, RemoteException}
import java.rmi.server.UnicastRemoteObject//这里就是实现了MyRemote trait
class MyRemoteImpl extends UnicastRemoteObject with MyRemote {@throws(classOf[RemoteException])override def sayHello(): String = {"Hello World!~"}}
//这里我们完成对服务(sayHello)注册任务->对服务管理
object MyRemoteImpl {def main(args: Array[String]): Unit = {val service: MyRemote = new MyRemoteImpl()//准备把服务绑定到9999端口【第一种注册方式】//LocateRegistry.createRegistry(9999)//Naming.rebind("RemoteHello", service)//准备把服务绑定到9999端口【第二种注册方式】Naming.rebind("rmi://127.0.0.1:9999/RemoteHello", service)println("远程服务开启,在127.0.0.1 的 9999端口监听,服务名 RemoteHello")}
}

调用服务

import java.rmi.Namingclass MyRemoteClient {def go() = {val service = Naming.lookup("rmi://127.0.0.1:9999/RemoteHello").asInstanceOf[MyRemote]val str = service.sayHello()println("str = " + str)}
}object MyRemoteClient {def main(args: Array[String]): Unit = {new MyRemoteClient().go()}
}

动态代理
动态代理:运行时动态的创建代理类(对象),并将方法调用转发到指定类(对象)
动态代理调用的机制图

1) Proxy 和 InvocationHandler 组合充当代理的角色.
2) RealSubject 是一个实际对象,它实现接口 Subject
3) 在使用时,我们不希望直接访问 RealSubject 的对象,比如:我们对这个对象的访问是有控制的
4) 我们使用动态代理,在程序中通过动态代理创建 RealSubject,并完成调用.
5) 动态代理可以根据需要,创建多种组合
6) Proxy 也会实现 Subject 接口的方法,因此,使用 Proxy+Invocation 可以完成对 RealSubject 的动态调用。
7) 但是通过 Proxy 调用 RealSubject 方法是否成功,是由 InvocationHandler 来控制的。(这里其实就是保护代理)
8) 理解: 创建一个代理对象替 代被调用的真实对象,使用 反射实现控制

动态代理的应用案例
应用案例说明
有一个婚恋网项目,女友/男友有个人信息、兴趣爱好和总体评分,要求:
1) 不能自己给自己评分
2) 其它用户可以评分,但是不能设置信息,兴趣爱好。
3) 请使用动态代理实现保护代理的效果。
4) 分析这里我们需要写两个代理。一个是自己使用,一个是提供给其它用户使用。

动态代理就是动态的控制各个角色的权限.

//这个就是我们的Subject(是一个trait/Java中interface)
trait PersonBean {def getName(): Stringdef getGender(): Stringdef getInterests(): Stringdef getScore(): Intdef setName(name: String)def setGender(gender: String)def setInterests(interests: String)def setScore(score:Int)    //这个信息就是自己不能调用,别人可以,动态的控制
}

自己的代理类

//自己调用的代理
class OwnerInvocationHandler extends InvocationHandler {//被调用的对象PersonBeanImplvar person: PersonBean = _//构造器def this(person: PersonBean) {thisthis.person = person}//说明//1.这里的proxy就是和OwnerInvocationHandler合作的代理@throws(classOf[Throwable])override def invoke(proxy: scala.Any, method: Method, args: Array[AnyRef]): AnyRef = {//如果是get方法就直接调用if (method.getName().startsWith("get")) {return method.invoke(person)//自己不能调用setHotOrNotRating,给自己评分} else if (method.getName().equals("setScore")) {//返回一个异常,同时invoke throws掉了return new IllegalAccessException()//如果是set方法就直接调用} else if (method.getName().startsWith("set")) {return method.invoke(person,args(0).toString)}null}
}

其它用户的代理类

//其它用户调用的
class NonOwnerInvocationHandler extends InvocationHandler {var person: PersonBean = _//构造器def this(person: PersonBean) {thisthis.person = person}//说明//1.这里的proxy就是和NonOwnerInvocationHandler合作的代理@throws(classOf[Throwable])override def invoke(proxy: scala.Any, method: Method, args: Array[AnyRef]): AnyRef = {//如果是get方法就直接调用if (method.getName().startsWith("get")) {return method.invoke(person)//其它用户可以调用setHotOrNotRating,进行评分} else if (method.getName().equals("setScore")) {return method.invoke(person, Integer.valueOf(args(0).toString))//其它用户不能调用set方法} else if (method.getName().startsWith("set")) {return new IllegalAccessException()}null}
}
//这个是要被调用的对象.
class PersonBeanImpl extends PersonBean {var name = ""var gender = ""var interests = ""var score :Int = _ // 评分值override def getName(): String = {return name}override def getGender(): String = {gender}override def getInterests(): String = {interests}override def setName(name: String): Unit = {this.name = name}override def setGender(gender: String): Unit = {this.gender = gender}// 自己可以调用// 其它用户不能调用override def setInterests(interests: String): Unit = {this.interests = interests}override def getScore(): Int = {score}//自己不能调用//其它用户可以调override def setScore(score: Int): Unit = {this.score = score}
}

主程序测试

import java.lang.reflect.Proxyclass MatchService {//创建了一个Personval tom = getPersonInfo("tom", "男", "爱好编程")//得到一个给自己调用的代理对象,它替代被调用的对象val OwnerProxy = getOwnerProxy(tom)println("Name is " + OwnerProxy.getName()) // tomprintln("Interests is " + OwnerProxy.getInterests()) // 爱好编程OwnerProxy.setInterests("爱好淘宝~")println("Interests is " + OwnerProxy.getInterests()) // 爱好淘宝~//自己给自己设置评分,通过代理控制,不能成功OwnerProxy.setScore(100) //刷分不成功!println("Score is " + OwnerProxy.getScore()) //分值仍然为 0println("****测试NonOwnerInvocationHandler**********")val mary = getPersonInfo("mary", "女", "爱好购物...")//返回一个其用户调用的代理对象val nonOwnerProxy = getNonOwnerProxy(mary)println("Name is " + nonOwnerProxy.getName()) // maryprintln("Interests is " + nonOwnerProxy.getInterests()) // 爱好购物...//其它人不能修改兴趣,通过代理进行控制不能调用setInterestsnonOwnerProxy.setInterests("爱好小猫咪~~") //失败,在动态代理控制println("Interests is " + nonOwnerProxy.getInterests()) //爱好购物...nonOwnerProxy.setScore(68) //其它人可以评分okprintln("score is " + nonOwnerProxy.getScore()) // 68def getPersonInfo(name: String, gender: String, interests: String): PersonBean = {val person = new PersonBeanImpl()person.setName(name)person.setGender(gender)person.setInterests(interests)person}def getOwnerProxy(person: PersonBean): PersonBean = {Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person)).asInstanceOf[PersonBean]}def getNonOwnerProxy(person: PersonBean): PersonBean = {Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(),new NonOwnerInvocationHandler(person)).asInstanceOf[PersonBean]}
}object MainTest {def main(args: Array[String]): Unit = {var mMatchService: MatchService = new MatchService()}
}

几种常见的代理模式介绍— 几种变体
1) 防火墙代理
内网通过代理穿透防火墙,实现对公网的访问。
2) 缓存代理
比如:当请求图片文件等资源时,先到缓存代理取,如果取到资源则 ok,如果取不到资源,再到公网或者数据库取,然后缓存。
3) 静态代理
静态代理通常用于对原有业务逻辑的扩充。
比如持有第二方包的某个类,并调用了其中的某些方法。比如记录日志、打印工作等。可以创建一个
代理类实现和第二方方法相同的方法,通过让代理类持有真实对象,调用代理类方法,来达到增加业
务逻辑的目的。
4) Cglib 代理
使用 cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm 字节码生成框架生成代理类的字节码。
5) 同步代理
主要使用在多线程编程中,完成多线程间同步工作

设计模式之代理模式-05相关推荐

  1. 【设计模式】代理模式 ( 动态代理 | 模拟 Java 虚拟机生成对应的 代理对象 类 )

    文章目录 前言 一.模拟 JVM 生成对应的 代理对象 二.模拟 JVM 生成对应的 代理对象 完整流程展示 1.目标对象接口 2.被代理对象 3.调用处理程序 4.模拟 JVM 生成的代理对象类 5 ...

  2. C++设计模式之代理模式

    这篇文章主要介绍了C++设计模式之代理模式,本文讲解了什么是代理模式.代理模式的使用场合.代理模式的实现代码等内容,需要的朋友可以参考下 前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就 ...

  3. python中代理模式分为几种_Python设计模式之代理模式实例详解

    本文实例讲述了Python设计模式之代理模式.分享给大家供大家参考,具体如下: 代理模式(Proxy Pattern):为其他对象提供一种代理以控制对这个对象的访问 #!/usr/bin/env py ...

  4. 设计模式笔记——代理模式

    设计模式笔记--代理模式 代理模式介绍 代理模式通常是介于请求方和提供方的一个中介系统,请求方是发送请求的一方,提供方是根据请求提供相应资源的一方 Web中的代理服务器就是一个例子,客户端向代理服务器 ...

  5. 「设计模式(五) - 代理模式」

    「设计模式(五) - 代理模式」 一.处处可见的"代理" "代理"在平常生活司空见惯,点外卖,租房子找中介,买飞机票等等.基本上用手机就能完成,也就是不直接接触 ...

  6. Javascript 设计模式之代理模式【讲师辅导】-曾亮-专题视频课程

    Javascript 设计模式之代理模式[讲师辅导]-969人已学习 课程介绍         随着 javascript ES6/7 的发布,很多老版本的设计模式的实现,今天来看是错误的,将被彻底. ...

  7. 设计模式之一代理模式

    代理模式(代理设计模式) 代理模式的定义与特点 代理模式的结构与实现 代理模式(代理设计模式) 在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代 ...

  8. 23种设计模式7_代理模式之一静态代理

    23种设计模式7_代理模式之一静态代理 1 基本介绍 代理模式:为其他对象提供一种代理以控制对这个对象的访问 代理模式也叫委托模式,它是一项基本设计技巧.许多其他的模式,如状态模式.策略模式.访问者模 ...

  9. Java中的设计模式:“代理模式”的理解

    代理模式定义: 为其他对象提供一种代理以控制对这个对象的访问.在面向对象中,有时候直接访问一些对象比较麻烦,所以代理模式就是在这个对象上加上一个访问该对象的访问层.类似于很多明星的事务实际都是交给经纪 ...

最新文章

  1. SQLServer执行命令出现“目录无效的提示”
  2. OpenCV的基本模块介绍
  3. 第12篇:Flowable-BPMN操作流程之用户任务UserTask
  4. linux重启memcache_linux下启动和停止memcached
  5. 数据结构课程设计——宿舍管理查询软件
  6. java考勤表导出_考勤打卡机导出的excel考勤时间表如何生成实用的考勤表
  7. 95后阿里P7晒出工资单:狠补了这个,真香…
  8. 使用js正则匹配和替换淘口令边界
  9. 微信公众平台消息接口开发(8)小黄鸡(小贱鸡)机器人
  10. 谷歌翻译器-在线实时批量谷歌翻译器
  11. 【Skill】解决 QQ 邮箱无法更改发信人名称问题
  12. adb命令——adb命令大全
  13. 计算机图形学——光线追踪(RayTracing)算法
  14. dzzoffice应用如何安装
  15. clickhouse PARTITION操作
  16. 参考文献的类型--参考文献里的J、M等字母都代表什么
  17. 基于JSP的宠物狗交易网站
  18. android10热点验证身份,通过Android的AccountManager类进行Twitter身份验证
  19. golang 如何快速测试代码
  20. 困扰老子好久啊!!tomcat的两个错…

热门文章

  1. MySQL - 索引类型详解
  2. 如何检测网站是否存在XSS跨站漏洞
  3. 测试用例设计的八大要素
  4. 域控服务器排查命令,mimikatz利用zerologon攻击域控服务器相关命令(附蓝队自查方案)...
  5. Virtualized Firewall for Cloud Security: Working on Machines Identities, NOT on Their IP Addresses
  6. 腾讯的另一面:开放连接下的可持续社会价值创新践行者
  7. 【分布式限流】你被12306的验证码坑过么?
  8. iptable防火墙
  9. 仿 iPhone Assistivetouch 自定义view
  10. 客户的安全性和透明度才是重要的