设计模式学习五、代理模式
来源:互联网 发布:淘宝卖家要在哪看粉丝 编辑:程序博客网 时间:2024/06/16 15:57
一、什么是代理模式?
为另一个对象提供一个替身或一个占位符以控制对这个对象的访问。
二、 代理模式各种变体。
远程代理:使得客户端可以访问在远程主机的角色(两个程序不在同一个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;//其他人不能修改name private int age;//其他人不能修改age private int rate;//本人不能修改rate @Override public void setName(String name) { this.name=name; } @Override public void setAge(int age) { this.age=age; } @Override public void setRate(int value) { this.rate=value; } @Override public String getName() { return name; } @Override public int getAge() { return age; } @Override public int getRate() { return rate; }}
创建两个InvocationHandler:
public class OwnerInvocationHandler implements InvocationHandler {//所调用的处理器都必须实现这个接口 private PersonBean personBean; public OwnerInvocationHandler(PersonBean personBean){//将personBean引入保持对它的引用 this.personBean=personBean; } @Override public 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")){//对于自己,不能修改rate throw new UnsupportedOperationException("不支持此项操作"); }else { return method.invoke(personBean,args); } }}
public class NoInvocationHandler implements InvocationHandler { private PersonBean personBean; public NoInvocationHandler(PersonBean personBean){ this.personBean=personBean; } @Override public 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与age throw 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内置的代理支持,可以根据需要创建动态代理。并将所有调用分配到所选的处理器。
- 设计模式学习五、代理模式
- 设计模式五:代理模式
- 大话设计模式学习(五)——代理模式
- 设计模式学习笔记(五)之代理模式(Proxy)
- 设计模式学习----代理模式
- 设计模式学习-----代理模式
- 设计模式学习--代理模式
- 设计模式学习--代理模式
- 设计模式学习--代理模式
- 设计模式学习-代理模式
- 学习设计模式-代理模式
- 设计模式学习-代理模式
- 大话设计模式(五)代理模式
- 设计模式之五 --- 代理(Proxy)模式
- 设计模式之五 --- 代理(Proxy)模式
- 设计模式之五 --- 代理(Proxy)模式
- 设计模式之五 --- 代理(Proxy)模式
- 设计模式培训之五:代理模式
- shell 函数 入参说明
- 常用SQL的优化
- hihocoder #1620 : 股票价格3
- UITableView判断reloadData结束
- js对象、继承,原型链相关知识的复习及应用心得
- 设计模式学习五、代理模式
- 易买网之分页显示对应当前页扥所有的商品1
- Linux下开发-exec
- viewpager和fragment的联动
- 第。一。篇。博。客。
- 11.2-关于自动备份文件 Python-使用Python编写的文件备份程序
- 欢迎使用CSDN-markdown编辑器
- 【C++】智能指针
- Linux学习笔记-常用命令详解