一、什么是代理模式?

为另一个对象提供一个替身或一个占位符以控制对这个对象的访问。

二、 代理模式各种变体。

远程代理:使得客户端可以访问在远程主机的角色(两个程序不在同一个jvm虚拟机)。

虚拟代理:当创建开销大的对象的时候,真正需要这个对象才创建它,当对象在创建前与创建中时候,由虚拟代理扮演对象替身的角色

保护代理:主要用于当前对象有不同访问权限时。(通过java的动态代理实现)

三、代理模式组成

抽象角色:代理类与真实类实现的共同的接口

真实角色:实现接口的功能。是真正做事的对象

代理角色:持有真实角色的引用,控制对真实角色的访问。

客户与真实角色的访问必须通过代理角色。任何出现真实角色的地方都可以被代理角色所替代。

四、具体实现

先说一下远程代理:

远程代理实现方式(rmi):

问题:有一家糖果机公司,CEO希望能写一个程序在远程查询糖果机中糖果的数量(ps:也就是查看数量的客户端与糖果机系统运行的服务端不在同一个JVM下)

首先,制作远程接口:注意:每一个方法都必须要抛出RemoteException异常。

//糖果机监视器,继承Remote接口。里面包含了需要的查询糖果数量的方法。
public interface SugerMachineMoniter extends Remote{public Integer getCount() throws RemoteException;
}

然后,编写服务端,服务端继承UnicastRemoteObject类,并实现SugerMachineMoniter接口

public class SugerMachine  extends UnicastRemoteObject implements SugerMachineMoniter{private Integer count;protected SugerMachine(int count) throws RemoteException {super();this.count=count;}@Overridepublic Integer getCount() throws RemoteException{return count;}
}

将编写的服务端注册到rmi服务器,供远程客户端调用。

public class Server {public static void main(String args[]){try {LocateRegistry.createRegistry(8888);//注册远程用户访问的端口SugerMachine sugerMachine=new SugerMachine(50);Naming.rebind("myServer", sugerMachine);//注册到rmi服务器上,访问的话就通过  rmi://服务器地址/注册名(这里是myServer)} catch (RemoteException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (MalformedURLException e) {// TODO Auto-generated catch blocke.printStackTrace();} }
}

远程客户端调用:

public class Client {public static void main(String args[]) throws MalformedURLException, RemoteException, NotBoundException{SugerMachineMoniter sugerMachineMoniter=(SugerMachineMoniter) Naming.lookup("rmi://127.0.0.1:8888/myServer");System.out.println(sugerMachineMoniter.getCount());}
}

分析:这里面如何用到代理的?(详细的搜一下rmi的详解)

这需要查看一下rmi的运行过程,客户端调用的对象(也就是SugerMachineMoniter),其实是调用的服务器端生成的远程对象的本地代理(Stub)。我们在客户端调用的时候,每调用一个方法,客户端的代理对象(stub)把信息打包发送给服务端,服务端解包并调用真正的服务端的代码。服务端代码再把反悔信息打包返回给客户端的代理(Stub),所以看起来就像是调用真正的对象。

再说一下保护代理(通过Java动态代理实现):

具体问题:有一个交友网站上传个人信息资料,包括三部分(姓名,年龄,热门程度)。本人无法修改热门程度可以修改其他,其他人可以修改这个人的热门程度不可以修改其他(,,,,假装这样做是对的,,,)。

分析:这时候你需要创建两个动态代理,一个用于保护本人修改信息的时候不能修改热门程度,其他人修改这个人信息时候只能修改热门程度。

具体代码:

首先:创建需要修改的Person对象:

public interface PersonBean {//这是一个接口public void setName(String name);public void setAge(int age);public void setRate(int value);public String getName();public int getAge();public int getRate();
}
public class PersonBeanImpl implements PersonBean {//具体实现类private String name;//其他人不能修改nameprivate int age;//其他人不能修改ageprivate int rate;//本人不能修改rate@Overridepublic void setName(String name) {this.name=name;}@Overridepublic void setAge(int age) {this.age=age;}@Overridepublic void setRate(int value) {this.rate=value;}@Overridepublic String getName() {return name;}@Overridepublic int getAge() {return age;}@Overridepublic int getRate() {return rate;}
}

创建两个InvocationHandler:

public class OwnerInvocationHandler implements InvocationHandler {//所调用的处理器都必须实现这个接口private PersonBean personBean;public OwnerInvocationHandler(PersonBean personBean){//将personBean引入保持对它的引用this.personBean=personBean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//每次调用personBean方法的时候,都是调用的它if (method.getName().contains("get")){return method.invoke(personBean,args);}else if (method.getName().equals("setRate")){//对于自己,不能修改ratethrow  new UnsupportedOperationException("不支持此项操作");}else {return method.invoke(personBean,args);}}
}
public class NoInvocationHandler implements InvocationHandler {private PersonBean personBean;public NoInvocationHandler(PersonBean personBean){this.personBean=personBean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Exception {if (method.getName().contains("get")) {return method.invoke(personBean,args);}else if (method.getName().equals("setRate")){return method.invoke(personBean,args);}else {                                        //对于别人,不能修改name与agethrow new Exception("不支持此项操作");}}
}

创建Proxy并实例化Proxy对象:我用两个方法实现的

    public  static  PersonBean getOwnerInvocation(PersonBean personBean){return (PersonBean) Proxy.newProxyInstance(personBean.getClass().getClassLoader(),//利用Proxy的静态方法创建代理,需要的参数:需要动态代理personBean.getClass().getInterfaces(),              //的对象的classLoader,所实现的接口,需要调用的invocationhandler     new OwnerInvocationHandler(personBean));}public  static  PersonBean getNoInvocation(PersonBean personBean){return (PersonBean) Proxy.newProxyInstance(personBean.getClass().getClassLoader(),personBean.getClass().getInterfaces(),new NoInvocationHandler(personBean));}

使用:

        PersonBean personBean=new PersonBeanImpl();personBean.setName("luck");personBean.setAge(12);personBean.setRate(6);PersonBean ownerPerson = getOwnerInvocation(personBean);try {ownerPerson.setRate(8);}catch (Exception e){System.out.println("这项操作不支持");}System.out.println(ownerPerson.getName()+","+ownerPerson.getRate()+","+ownerPerson.getAge());PersonBean otherPerson=getNoInvocation(personBean);try{otherPerson.setAge(10);}catch (Exception e){System.out.println("不支持此方法");}otherPerson.setRate(10);System.out.println(otherPerson.getName()+"."+otherPerson.getAge()+","+otherPerson.getRate());}

输出:

这项操作不支持
luck,6,12
不支持
luck.12,10

ps:动态代理之所以称为动态代理,在系统运行时候它才创建出来。

五、总结:

一、代理模式作为一个代表,以便控制客户对真实对象的访问,控制方式有很多种。

二、远程代理管理客户和远程对象的交互,虚拟代理控制访问实例化开销大的对象,保护代理基于调用者控制对象方法的访问

三、代理在结构上类似装饰者,但是目的不同,装饰者模式为对象加上行为,而代理是控制访问  。

四、Java内置的代理支持,可以根据需要创建动态代理。并将所有调用分配到所选的处理器。

转载于:https://www.cnblogs.com/GregZQ/p/8365280.html

设计模式学习五、代理模式相关推荐

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

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

  2. 设计模式学习笔记-代理模式

    1. 概述 为其它对象提供一种代理以控制对这个对象的访问. 解决的问题:如果直接访问对象比较困难,或直接访问会给使用者或系统带来一系列问题.这样对于客户端(调用者)来说,就不需要直接与真实对象进行交互 ...

  3. 设计模式学习笔记——代理(Proxy)模式

    设计模式学习笔记--代理(Proxy)模式 @(设计模式)[设计模式, 代理模式, proxy] 设计模式学习笔记代理Proxy模式 基本介绍 代理案例 类图 实现代码 Printable接口 Pri ...

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

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

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

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

  6. 《设计模式系列》- 代理模式

    有情怀,有干货,微信搜索[三太子敖丙]关注这个有一点点东西的程序员. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的系列文 ...

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

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

  8. Java设计模式学习 - 模版方法模式策略模式

    个人博客项目地址 希望各位帮忙点个star,给我加个小星星✨ 设计模式-模板方法&策略模式 简单介绍 模板方法模式(Template):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. ...

  9. 设计模式 - 学习笔记 - 工厂模式Factory Pattern

    设计模式 - 学习笔记 - 工厂模式Factory Pattern 1. 简单工厂 1.1 应用场景 1.2 UML 1.3 优劣分析 好处 缺点 1.4 代码示例 抽象产品 AbstractProd ...

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

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

最新文章

  1. 遗传算法c语言程序,遗传算法c语言代码.doc
  2. bada 2D游戏编程之十——关键帧动画原理
  3. 数据结构期末考试题目---笔记(SYSU)
  4. 交互式计算机图形学总结:第四章 观察
  5. vue中安装使用echarts
  6. qt布局嵌套_QDockWidget嵌套布局详解-实现Visual Studio布局
  7. MFC初探 —— 文件与文件夹的选择与拷贝
  8. MLP多层感知机原理简介+代码详解
  9. 用shell把所有文件名修改为小写
  10. 继承与data member之多重继承
  11. 【优化算法】阿基米德优化算法(AOA)【含Matlab源码 1447期】
  12. java中常量池存的是什么_Java中常量池是什么?Java常量池的介绍
  13. profibus通讯快速入门_西门子S7-300/400PLC入门:硬件配置
  14. 有道云笔记linux使用教程,我是这么用有道云笔记的!
  15. micropython stm32f107_stm32f107 USART3数据接收错误问题
  16. 从我那句名言“系统上线之日,需求开始之时”谈大型信息化系统建设的那些坑
  17. 【笔记】LaTex安装及使用(五)Endnote批量查找、导入和导出参考文献
  18. Ubuntu实用工具/软件汇总
  19. 诋毁PlusFo究竟有何意义?
  20. WELL HSR找标识行动起航 - 跨行业国际明星巨匠为“WELL 健康-安全评价”代言

热门文章

  1. oracle改成归档模式_将Oracle数据库改为归档模式并启用Rman备份
  2. iframe重新加载与修改提交不关闭窗口属性页面
  3. Map<String,Object> map=new HashMap<String,Object>详解
  4. matlab breline,linebreak_header must be terminated by a line break怎么解决
  5. 模板模式 php,PHP设计模式5-模板模式
  6. ajax=1,ajax专栏1
  7. html不同类别的列表设置,HTML --列表
  8. 将图像转为特征值_用K均值进行图像分割
  9. android p获取通话记录_Android 底层的进程间同步机制
  10. nginx高性能web服务器详解_Nginx服务器高性能优化轻松实现10万并发访问量