代理模式可以分为以下四类

  • 远程代理(Remote Proxy):控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
  • 虚拟代理(Virtual Proxy):根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
  • 保护代理(Protection Proxy):按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
  • 智能代理(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作:记录对象的引用次数;当第一次引用一个对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。

1 远程代理设计模式

1.1 应用场景

为一个对象在不同地址空间提供局部代表这样可以隐藏一个对象存在于不同地址空间的事实,例如:老阮(MrRuan)在地点A,老李在地点B,餐厅柜台也在地点乙,那么老李和老软住在一起(都在地点甲住),那么老李就是餐厅(地点B)在老软与老李住处(地点A)的代表。

1.2 概念

代理设计模式为另一个对象提供一个替身或者占位符用以控制对这个对象的访问。使用代理模式创建代表(representative)对象,让代表对象控制某个对象的访问,被代理的对象可以是远程的对象、创建开销很大的对象或者是需要安全控制的对象。

1.3 Class Diagram

首先是Subject,它是RealSubject和Proxy提供了相同的接口。通过实现同一个接口,Proxy在RealSubject出现的地方取代它。RealSubject才是真正做事的对象,它是被proxy代理和控制访问的对象。Proxy持有RealSubject的引用,因为Proxy和RealSubject实现相同的接口,所以任何用到RealSubject的地方,都可以用Proxy取代。Proxy也控制了对RealSubject的访问,在某些情况下,我们可能需要这样的控制。这些情况包括RealSubject是远程的对象,RealSubject创建开销大或者RealSubject需要被保护。

1.4 Implementation

下面展示一个远程代理设计模式的实现:

1. 远程代理类接口Subject
public interface GumballMachineRemote extends Remote {public int getCount() throws RemoteException;public String getLocation() throws RemoteException;public State getState() throws RemoteException;
}2. RealSubject接口正在的实现类
public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote {private State soldOutState;private State noQuarterState;private State hasQuarterState;private State soldState;private State winnerState;private State state;private int count = 0;private String location;public GumballMachine(String location, int numberGumballs) throws RemoteException {soldOutState = new SoldOutState(this);noQuarterState = new NoQuarterState(this);hasQuarterState = new HasQuarterState(this);soldState = new SoldState(this);winnerState= new WinnerState(this);this.count = numberGumballs;this.location=location;if (numberGumballs > 0) {state = noQuarterState;} else {state = soldOutState;}}public void insertQuarter() {state.insertQuarter();}public void ejectQuarter() {state.ejectQuarter();}public void turnCrank() {state.turnCrank();state.dispense();}void releaseBall() {System.out.println("A gumball comes rolling out the slot...");if (count != 0) {count = count - 1;}}public int getCount() {return count;}void refill(int count) {this.count += count;System.out.println("The gumball machine was just refilled; it's new count is: " + this.count);state.refill();}void setState(State state) {this.state = state;}public State getState() {return state;}public State getSoldOutState() {return soldOutState;}public State getNoQuarterState() {return noQuarterState;}public State getHasQuarterState() {return hasQuarterState;}public State getSoldState() {return soldState;}public State getWinnerState() {return winnerState;}public String getLocation() {return location;}public void setLocation(String location) {this.location = location;}public String toString() {StringBuffer result = new StringBuffer();result.append("\nMighty Gumball, Inc.");result.append("\nJava-enabled Standing Gumball Model #2004");result.append("\nInventory: " + count + " gumball");if (count != 1) {result.append("s");}result.append("\n");result.append("Machine is " + state + "\n");return result.toString();}
}3. 通过在“classes”目录下执行:rmic com.basic.proxypattern.gumball.GumballMachine 命令生成客户端辅助类Stub和服务器辅助类Skeleton类。4. 通过在“classes”目录下执行:rmiregistry 启动RMI Registry服务5. 将我们的GumballMachineRemote注册到RMI Registry服务中去public class GumballMachineRemoteTestDrive {public static void main(String[] args) throws RemoteException {GumballMachineRemote gumballMachineRemote=null;int count=0;if (args.length > 2 ){System.out.println("GumballMachine <name> <inventory>");System.exit(0);}try {count=Integer.parseInt(args[1]);gumballMachineRemote=new GumballMachine(args[0],count);Naming.rebind("//"+args[0]+"/gumballmachine",gumballMachineRemote);} catch (MalformedURLException e) {e.printStackTrace();}}
}6. 这个时候就可以在客户端调用RMI Reigistry注册过的服务了public class GumballMointorRemoteTestDrive {public static void main(String[] args){try {GumballMachineRemote machine= (GumballMachineRemote) Naming.lookup("rmi://localhost/gumballmachine");GumballMonitor gumballMonitor=new GumballMonitor(machine);gumballMonitor.report();} catch (NotBoundException e) {e.printStackTrace();} catch (MalformedURLException e) {e.printStackTrace();} catch (RemoteException e) {e.printStackTrace();}}
}

通过调用代理的方法,远程调用可以跨过网络,返回字符串、整数和State对象。因为我们使用的是代理,调用的方法会在远程执行。

  1. CEO执行监视器,先取得远程糖果机的代理,然后调用每个代理的getState()、getCount()和getLocation()方法。
  2. 代理上的getState被调用,此调用转发到远程服务上。远程服务器辅助类Skeleton接收到请求,然后转发给糖果机。
  3. 糖果机将状态返回给Skeleton,skeleton将状态序列化,通过网络传回给代理,代理将其反序列化,把它当做一个对象返回给监视器。

2. 虚拟代理设计模式

2.1 应用场景

是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真是对象,例如:老阮(MrRuan)在地点A,到餐厅柜台(地点B),因为距离远却是很费劲,而老李刚好在这里(地点B)上班,所以让老李去办是很可行的办法。

2.2 概念

虚拟代理作为创建开销大的对象的代表。虚拟代理经常知道我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由虚拟代理来扮演对象的替身。对象创建之后,代理就会将请求直接委托给对象

2.3 Class Diagram

这是一个根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问。

2.4 Implementation

public class ImageProxy implements Icon {private ImageIcon imageIcon;private URL url;private Thread retrievalThread;private boolean retrieving = false;public ImageProxy(URL url) {this.url = url;}@Overridepublic void paintIcon(final Component c, Graphics g, int x, int y) {if(imageIcon!=null){imageIcon.paintIcon(c,g,x,y);}else {g.drawString("Loading CD cover , pleas wait...",x+300,y+190);if(!retrieving){retrieving=true;retrievalThread=new Thread(new Runnable() {@Overridepublic void run() {try {imageIcon=new ImageIcon(url, "CD cover");c.repaint();} catch (Exception e) {e.printStackTrace();}}});retrievalThread.start();}}}@Overridepublic int getIconWidth() {if(imageIcon != null){return imageIcon.getIconWidth();}elsereturn 800;}@Overridepublic int getIconHeight() {if(imageIcon != null){return imageIcon.getIconHeight();}elsereturn 600;}
}class ImageComponent extends JComponent {private static final long serialVersionUID = 1L;private Icon icon;public ImageComponent(Icon icon) {this.icon = icon;}public void setIcon(Icon icon) {this.icon = icon;}public void paintComponent(Graphics g) {super.paintComponent(g);int w = icon.getIconWidth();int h = icon.getIconHeight();int x = (800 - w)/2;int y = (600 - h)/2;icon.paintIcon(this, g, x, y);}
}public class ImageProxyTestDrive {ImageComponent imageComponent;JFrame frame = new JFrame("CD Cover Viewer");JMenuBar menuBar;JMenu menu;Hashtable<String, String> cds = new Hashtable<String, String>();public static void main (String[] args) throws Exception {ImageProxyTestDrive testDrive = new ImageProxyTestDrive();}public ImageProxyTestDrive() throws Exception{cds.put("Buddha Bar","http://images.amazon.com/images/P/B00009XBYK.01.LZZZZZZZ.jpg");cds.put("Ima","http://images.amazon.com/images/P/B000005IRM.01.LZZZZZZZ.jpg");cds.put("Karma","http://images.amazon.com/images/P/B000005DCB.01.LZZZZZZZ.gif");cds.put("MCMXC A.D.","http://images.amazon.com/images/P/B000002URV.01.LZZZZZZZ.jpg");cds.put("Northern Exposure","http://images.amazon.com/images/P/B000003SFN.01.LZZZZZZZ.jpg");cds.put("Selected Ambient Works, Vol. 2","http://images.amazon.com/images/P/B000002MNZ.01.LZZZZZZZ.jpg");URL initialURL = new URL((String)cds.get("Selected Ambient Works, Vol. 2"));menuBar = new JMenuBar();menu = new JMenu("Favorite CDs");menuBar.add(menu);frame.setJMenuBar(menuBar);for (Enumeration<String> e = cds.keys(); e.hasMoreElements();) {String name = (String)e.nextElement();JMenuItem menuItem = new JMenuItem(name);menu.add(menuItem);menuItem.addActionListener(event -> {imageComponent.setIcon(new ImageProxy(getCDUrl(event.getActionCommand())));frame.repaint();});}// set up frame and menusIcon icon = new ImageProxy(initialURL);imageComponent = new ImageComponent(icon);frame.getContentPane().add(imageComponent);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.setSize(800,600);frame.setVisible(true);}URL getCDUrl(String name) {try {return new URL((String)cds.get(name));} catch (MalformedURLException e) {e.printStackTrace();return null;}}
}

3. 保护代理设计模式

3.1 应用场景

保护代理模式就是一种可以根据访问权限决定客户可否访问对象的代理。比如,如果你有一个雇员对象,保护代理允许雇员调用对象上的某些方法,经理还可以多调用一些其他的方法(像setSlary()),而人力资源的雇员可以调用对象上的所有方法。

3.2 概念

按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。保护代理模式可以根据访问权限来决定客户是否可以访问对象的代理。

3.3 Class Diagram

Java在java.lang.reflect包中有自己的代理支持,利用这个包你可以在运行时动态地创建一个代理类,实现一个或者多个接口,并将方法的调用转发到你指定的类。因为实际的代理类是在运行时创建的,我们称这个Java技术为动态代理。

InvocationHandler的工作是响应代理的任何调用。你可以把InvocationHandler想成是代理收到方法调用后,请求实际工作的对象。

3.4 Implementation

public interface PersonBean {String getName();String getGender();String getInterests();int getHotOrNotRating();void setName(String name);void setGender(String gender);void setInterests(String interests);void setHotOrNotRating(int rating);}public class PersonBeanImpl implements PersonBean {String name;String gender;String interests;int rating;int ratingCount = 0;public String getName() {return name;   } public String getGender() {return gender;}public String getInterests() {return interests;}public int getHotOrNotRating() {if (ratingCount == 0) return 0;return (rating/ratingCount);}public void setName(String name) {this.name = name;}public void setGender(String gender) {this.gender = gender;} public void setInterests(String interests) {this.interests = interests;} public void setHotOrNotRating(int rating) {this.rating += rating;  ratingCount++;}
}public class NonOwnerInvocationHandler implements InvocationHandler{private PersonBean personBean;public NonOwnerInvocationHandler(PersonBean personBean) {this.personBean = personBean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if(method.getName().startsWith("get")){throw new IllegalAccessException();}else if(method.getName().startsWith("set")){throw new IllegalAccessException();}else if(method.getName().startsWith("setHotOrNotRating")){return method.invoke(personBean,args);}} catch (Exception e) {e.printStackTrace();}return null;}
}public class OwnerInvocationHandler implements InvocationHandler{private PersonBean personBean;public OwnerInvocationHandler(PersonBean personBean) {this.personBean = personBean;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {if(method.getName().startsWith("get")){return method.invoke(personBean,args);}else if(method.getName().startsWith("set")){return method.invoke(personBean,args);}else if(method.getName().startsWith("setHotOrNotRating")){throw new IllegalAccessException();}} catch (Exception e) {e.printStackTrace();}return null;}
}public class MatchMakingTestDrive {HashMap<String, PersonBean> datingDB = new HashMap<String, PersonBean>();public static void main(String[] args) {MatchMakingTestDrive test = new MatchMakingTestDrive();test.drive();}public MatchMakingTestDrive() {initializeDatabase();}public void drive() {PersonBean joe = getPersonFromDatabase("Joe Javabean"); PersonBean ownerProxy = getOwnerProxy(joe);System.out.println("Name is " + ownerProxy.getName());ownerProxy.setInterests("bowling, Go");System.out.println("Interests set from owner proxy");try {ownerProxy.setHotOrNotRating(10);} catch (Exception e) {System.out.println("Can't set rating from owner proxy");}System.out.println("Rating is " + ownerProxy.getHotOrNotRating());PersonBean nonOwnerProxy = getNonOwnerProxy(joe);System.out.println("Name is " + nonOwnerProxy.getName());try {nonOwnerProxy.setInterests("bowling, Go");} catch (Exception e) {System.out.println("Can't set interests from non owner proxy");}nonOwnerProxy.setHotOrNotRating(3);System.out.println("Rating set from non owner proxy");System.out.println("Rating is " + nonOwnerProxy.getHotOrNotRating());}PersonBean getOwnerProxy(PersonBean person) {return (PersonBean) Proxy.newProxyInstance( person.getClass().getClassLoader(),person.getClass().getInterfaces(),new OwnerInvocationHandler(person));}PersonBean getNonOwnerProxy(PersonBean person) {return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new NonOwnerInvocationHandler(person));}PersonBean getPersonFromDatabase(String name) {return (PersonBean)datingDB.get(name);}void initializeDatabase() {PersonBean joe = new PersonBeanImpl();joe.setName("Joe Javabean");joe.setInterests("cars, computers, music");joe.setHotOrNotRating(7);datingDB.put(joe.getName(), joe);PersonBean kelly = new PersonBeanImpl();kelly.setName("Kelly Klosure");kelly.setInterests("ebay, movies, music");kelly.setHotOrNotRating(6);datingDB.put(kelly.getName(), kelly);}
}

4. 其他代理设计模式

  • 防火墙代理(Firewall Proxy):控制网络资源的访问,保护主题免于“坏客户”的侵害。
  • 智能引用代理(Smart Reference Proxy):当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数。
  • 缓存代理(Caching Proxy):为开销大的运算结果提供暂时的存储:它也允许多个客户共享结果,以减少计算或者网络延迟。
  • 同步代理(Synchronized Proxy):在多线程的情况下为主题提供安全的访问。
  • 复杂隐藏代理(Complexity Hiding Proxy):用来隐藏一个类的复杂集合的复杂度,并进行访问控制。
  • 写入复制代理(Copy-On-Write Proxy):用来控制对象的复制,方法是延迟对象的复制,直到客户真正需要为止。

5. JDK

  • java.lang.reflect.Proxy
  • RMI

Java设计模式(十三):代理设计模式相关推荐

  1. Java二十三种设计模式 之代理(proxy)

    Java二十三种设计模式 之代理(proxy) 今天我们学习一下静态代理和动态代理 我们来看代码(写一个坦克运行了多少时间): 第一种方法: public calss Tank implements ...

  2. 设计模式(十三) 代理模式和Java动态代理

    Proxy Pattern 1. 什么是代理模式 代理模式: 给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问. Proxy Pattern: Provide a surrogate ...

  3. Java中的代理设计模式

    代理对象或代理对象为另一个对象提供占位符,以控制对该对象的访问. 代理充当原始对象的轻量级版本或简化版本. 它支持与原始对象相同的操作,但可以将那些请求委托给原始对象以实现它们. 代理设计模式是一种结 ...

  4. 外观模式和代理模式的联系和区别_设计模式之代理设计模式

    原文首发于微信公众号:jzman-blog,欢迎关注交流! 今天来看一下什么是代理设计模式,顾名思义,代理就是通过中介代替某人做某一件事,对应到我们的程序中就是通过代理对象来控制某个具体对象某个方法的 ...

  5. Java 二十三种设计模式

    一.单例模式 定义 Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有 ...

  6. java二十三种设计模式——工厂设计模式

    java设计模式的分类 在java中,设计模式有三十三种之多,分为三大类: 创建性模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构性模式,共七种:适配器模式.装饰器模式 ...

  7. 装饰设计模式,代理设计模式 最通俗易懂的案例

    import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer; import org.springfr ...

  8. GoF设计模式之代理设计模式

    该文章首发于GoF设计模式-代理模式 概述 代理模式(Proxy Pattern),为其他对象提供一种代理以控制对这个对象的访问. 代理模式其实就是在访问对象时引入一定程度的间接性,因为这种间接性,可 ...

  9. java之 代理设计模式

    1. 设计一个案例来实现租房功能.分析:在租房的过程中涉及到了3个对象,房东,中介,房客. 中介和房客具有相同的功能--租房. 可以设计如下: 2.上图的设计实际上就是一个代理设计模式---静态代理设 ...

  10. Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理

    面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问"茴香豆的茴字有哪几种写法?" 所谓代理模式,是指客户端(Cl ...

最新文章

  1. 日期时间类,按特定格式显示日期时间
  2. 在CentOS上安装Git
  3. 华为宣布了,手机将全面支持鸿蒙!
  4. CISCO网络故障排错命令总结分享
  5. 二开微信表情包小程序去授权版+网站后端
  6. 手把手教你学dsp_新课免费看| 手把手教你学DSP,C2000从入门到精通
  7. 图算法--深度优先/广度优先/最小生成树/最短路径
  8. 思科安全代理 CSA 概述
  9. mysql行列转换case_浅析SQL语句行列转换的两种方法 case...when与pivot函数的应用_MySQL...
  10. 一.反编译Apk得到Java源代码
  11. 【Codeforces Global Round 2】A-E题解 【Frets On Fire、Pavel and Triangles】
  12. 《嵌入式 – GD32开发实战指南》第15章 低功耗(电源管理)
  13. android 应用市场发布以及流程(非原创)
  14. 测试移动硬盘的真实容量的软件,移动硬盘容量标识有猫腻:实际缩水99%
  15. 如何使用AI绘制网格花卉?
  16. ModelSim 仿真常见问题及解决办法
  17. 重庆小飞龙前端第一天----了解html
  18. 借助于栈结构将一个单链表逆置
  19. 安防监控系统流媒体服务器,搭建一套安防监控系统RTSP/Onvif网络摄像头视频流媒体服务有哪些核心要素?...
  20. ios label文字行间距_iOS 设置label的行间距教程

热门文章

  1. CMake结合Visual Studio中开发Qt应用程序注意事项
  2. robotframework手机号随机产生脚本
  3. Codechef:Path Triples On Tree
  4. [hdu3966 Aragorn's Story]树链剖分
  5. 【转】Extending Lync Server routing with MSPL
  6. Android网络项目课程笔记-----代码复用性
  7. 云中家园FTP搜索站点开通
  8. 87.VGA 88.FPGA
  9. 深度学习概述:当你没有方向时的加油站
  10. pelco-d协议数据解析示例