代理模式

假设现在需要设置一个监视器Monitor,能够监视糖贩卖机GumballMachine的状态,位置信息、还有多少糖果等。一个简单的想法就是创建一个Monitor的类,构造参数包括GumballMachine。然后就可以调用GumballMachine的一些状态函数。

但是如果GumballMachine在另一台机器上、或者在不同的Java堆上,显然是不能够将GumballMachine的引用传递过来。

这是后就需要使用代理模式来解决。

思路:添加一个新的类叫做MonitorProxy。Monitor和MonitorProxy在一个Java堆上,MonitorProxy这个代理负责与远程的GumballMachine进行沟通,得到数据后把自己伪装成GumballMachine来被MonitorProxy调用。

远程方法

原理

我们要这设计这样一个系统:该系统允许我们调用本地的一个对象,本地的这个对象又能够将请求转发到远程对象上。

四个关键的角色 client 、client helper、service helper、Service

客户端

client helper的作用是让client调用和调用远程remoter效果一样。client helper处理转发了client的请求。

换句话说,从client的角度来看,client就是在调用一个远程的服务。client helper假装自己是service

client helper有和service一样的方法。但是他们的逻辑不同,client helper里面的方法是对service进行响应请求、然后进行参数转换返回给client的。

服务器端

同客户端一样,存在一个Service helper负责处理对话(可能是Socket)

Java RMI(Remote Method Invocation)

Java RMI已经封装好了相关功能。不需要自己动手写网络和I/O相关的代码了。和调用本地的对象一样。唯一的区别时会有网络通讯,可能引起失败抛出异常。

client helper 叫做RMI Stub

service helper 叫做RMI Skeleton

使用RMI

Remote service

一共五步走:

1. 写一个Remote 接口

这个远程接口所定义的方法是client远程调用的。这也就意味着stub和实际的service都要实现这个接口

//1. 扩展java.rmi.Remote接口
public interface MyRemote extends Remote{//2. 接口中所有的函数都要能够抛出RemoteException异常//因为涉及到网络或者I/O,可能出现连接错误等。public String sayHello() throws RemoteException;//3. 要保证参数和返回值都是基本的数据类型或者是可序列化的。
}

2. 实现Remote接口

远程的class要实现上一步定义的接口

// 1. 注意MyRemoteImpl所继承的类UnicastRemoteObject, 这个类定义了一些远程服务所需要的功能函数。
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{// 2. 抛出这个异常的原因是它的父类可能UnicastRemoteObject会抛出这个异常,所以子类也一样。public MyRemoteImpl() throws RemoteException{}public String sayHello() {return "server says, hi";// other impl}// 主函数入口。方便起见直接写在了这个类public static void main (String[] args) {/*方法一*/// 需要运行第四步命令try {MyRemote service = new MyRemoteImpl();Naming.rebind(“RemoteHello”, service); //在RMI中注册} catch(Exception ex) {ex.printStackTrace();}}/*方法二*///使用内在注册器,不用单独运行rmiregistry服务。try {//默认端口1099Registry registry = LocateRegistry.createRegistry(1099);MyRemoteImpl service = new MyRemoteImpl();registry.bind("RemoteHello", service); // 在RMI中注册System.out.println("Run Successfully");} catch (Exception ex) {ex.printStackTrace();}
}

定义好service,需要使用。方法就是把上面的MyRemoteImpl实例化之后,在RMI 中注册这个服务。

try{
MyRemote service = new MyRemoteImpl();
Naming.rebind(“RemoteHello”, service); //起一个名字并且注册。
}catch(Exception ex){

}

3. 生成stubs和skeletons(即service helper和client helper)(java1.5及以后不再被需要)可以略过。

使用rmic工具生成两个类:

rmic MyRemoteImpl
  • MyRemoteImpl_Stub.class 给client
  • MyRemoteImpl_Skel.class 给service

4. 运行RMI registry(在service主机上)

rmiregistry

确保运行的文件能够到达你的类。稳妥的办法是从你的类文件运行此命令。

例如从全限定类名的根目录开始。比如bin/test/MyRemoteImpl.class

那么从bin目录运行

5. 运行远程服务(在service主机上)

java MyRemoteImpl

xxxx是main函数的远程服务。

从全限定类名的根目录开始。同上。

Client

client如何能够得到stub object呢?

import java.rmi.*;
public class MyRemoteClient {// 主程序入口public static void main (String[] args) {new MyRemoteClient().go();}public void go() {try {//查找,返回时Object,需要Cast//如果是默认端口和本地地址,可以忽略不写MyRemote service = (MyRemote) Naming.lookup(“rmi://127.0.0.1:1099/RemoteHello”);String s = service.sayHello();System.out.println(s);} catch(Exception ex) {ex.printStackTrace();}}
}
  1. client去rmi注册表中查找RemoteHello(是注册时的名字)
  2. Client需要有远程的接口MyRemote.java

client如何获得stub这个类?

  • 方法一:手工交付
  • 方法二:动态下载。放到服务器上动态,如果本地搜索不到就是用http请求下来。

注意事项

  • 在远程服务启动之前,启动rmiregistry。service运行时调用了Naming.rebind(),这个需要rmiregistry服务。所以必须提前运行
  • 忘记使参数或者返回类型序列化。这个编译器检查不出来。只有运行时报错。
  • 忘记把stub给client。

代理模式定义

为另一个对象提供一个代理或者占位符,来控制对他的访问。

几个控制访问的方法:

  • 一个远程代理控制对远程对象的访问

  • 虚拟代理控制对创建成本较高的资源的访问

  • 保护代理控制对于权限资源的访问

远程代理

上面提的那种

虚拟代理

虚拟代理用来标识一个需要昂贵代价去创建的对象。虚拟代理通常来推迟这个对象的创建,直到这个对象被需要时再创建。在被代理对象创建完成之前,虚拟代理扮演者被代理者(RealSubject)的角色, 创建完成之后,虚拟代理把请求转交给被代理对象。

例如:播放在线音乐,当音乐封面没有被下载的时候,虚拟代理充当封面的角色(可以使一串字符串“正在下载封面”,或者其他的某个默认图片), 一旦封面下载完成,虚拟代理就把所有调用的方法委托给实际的图片。

// Head Fist Design Pattern P456
class ImageProxy implements Icon {ImageIcon imageIcon;URL imageURL;Thread retrievalThread;boolean retrieving = false;public ImageProxy(URL url) { imageURL = url; }public int getIconWidth() {if (imageIcon != null) {return imageIcon.getIconWidth();} else {return 800;}}public int getIconHeight() {if (imageIcon != null) {return imageIcon.getIconHeight();} else {return 600;}}public 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, please wait...”, x+300, y+190);if (!retrieving) {retrieving = true;retrievalThread = new Thread(new Runnable() {public void run() {try {imageIcon = new ImageIcon(imageURL, “CD Cover”);c.repaint();} catch (Exception e) {e.printStackTrace();}}});retrievalThread.start();}}}
}

设计模式(11)代理模式The Proxy Pattern - 1 - 远程代理rmi相关推荐

  1. Android常见设计模式——代理模式(Proxy Pattern)(二)

    文章目录 1. 前言 2. 远程代理(Remote Proxy) 3. 后记 1. 前言 在上篇Android常见设计模式--代理模式(Proxy Pattern)中基本上知道了什么是代理模式,以及对 ...

  2. Android常见设计模式——代理模式(Proxy Pattern)

    文章目录 1. 前言 2. 代理模式(Proxy Pattern) 2.1 静态代理模式 2.2 动态代理模式 3. Android 中的代理模式 3.1 Retrofit中的代理模式(没有被代理者) ...

  3. Net设计模式实例之代理模式(Proxy Pattern)

    一.代理模式简介(Brief Introduction) 代理模式(Proxy Pattern)对其他对象提供一种代理以控制对这个对象的访问. 二.解决的问题(What To Solve) 1.远程代 ...

  4. 【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理

    这篇博文,我们主要以类图和代码的形式来对照学习一下静态代理和动态代理.重点解析各自的优缺点. 定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并 ...

  5. C#设计模式之十二代理模式(Proxy Pattern)【结构型】

    一.引言 今天我们要讲[结构型]设计模式的第七个模式,也是"结构型"设计模式中的最后一个模式,该模式是[代理模式],英文名称是:Proxy Pattern.还是老套路,先从名字上来 ...

  6. 设计模式笔记15:代理模式(Proxy Pattern)

    一.代理模式的内容        代理模式为另一个对象提供一个替身或占位符以访问这个对象.         给某一个对象提供一个代理,并由代理对象控制对原对象的引用.代理模式的英文叫做Proxy或Su ...

  7. 代理对象我所理解的设计模式(C++实现)——代理模式(Proxy Pattern)

    文章结束给大家来个程序员笑话:[M] 概述 作为C++工程师,免不了要管理内存,内存管理也是C++中的难点,而智能指针采用引用计数的方法很方便的帮我们管理了内存的应用,极大方便了我们的任务效率.而智能 ...

  8. C#设计模式(13)——代理模式(Proxy Pattern)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

  9. 设计模式笔记——代理模式(Proxy Pattern)

    一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...

最新文章

  1. WPF 中动态创建和删除控件
  2. 由mysql分区想到的分表分库的方案
  3. BugkuCTF-Misc:做个游戏(08067CTF)
  4. Console的使用——Google Chrome代码调试
  5. 【渝粤教育】广东开放大学 网络整合营销 形成性考核 (53)
  6. 探测活动主机的代码linux,Linux入侵痕迹检测方案【华为云技术分享】
  7. 关于“100g文件全是数组,取最大的100个数”解决方法汇总
  8. ai 自动外呼 微信加好友_制作一个可爱的Pwnagotchi AI好友来自动审核Wi-Fi网络
  9. 易中天:望子成人,而非望子成龙
  10. MQX4.0:MK60DZ10.h头文件GPIO模块…
  11. 【智能手环APP for Android 】01 百度地图展示行动轨迹
  12. c语言对数组取反,C语言中按逆取反是什么意思
  13. 自由 Freedom
  14. pikachu之xss漏洞学习
  15. 7-86 小明的晚饭 (50分)
  16. python编写我的世界
  17. brew Error: Cask ‘adoptopenjdk8‘ is unreadable
  18. 恩科迪亚Encodya for mac(单机游戏)
  19. 【Simulink教程案例4】使用Simulink自带的模块实现PID控制器,并对比案例1的PID控制器
  20. 51Nod - 1588 幸运树(DFS)

热门文章

  1. Android 4.1~4.3 Jelly Bean
  2. 结构型模式——组合模式(Composite)
  3. 什么是图灵完备语言?
  4. python i+=1与i=i+1的区别
  5. 《海底两万里》的读书笔记作文4000字
  6. 蓝桥杯——2018第九届C/C++真题[省赛][B组]
  7. 三星盖世4上手测评分享
  8. 步进电机H桥驱动电路设计 【转】
  9. 1.2 CSS 基础
  10. 音视频技术开发周刊 | 297