《深入浅出设计模式之代理模式》由会员分享,可在线阅读,更多相关《深入浅出设计模式之代理模式(66页珍藏版)》请在金锄头文库上搜索。
1、代理模式代理 企业老总门口总有一个办公室的秘书 很多企业门口有保安 老总和蔼可亲 秘书凶巴巴的糖果机例子 上次课的糖果机例子,现在有了一个新需 求,CEO需要知道分布在各地的糖果机的 状况:糖果机剩余的糖果多少?(是否需 要补充)糖果机目前的状况 如银行需要了解每一个ATM机的状况:现 金多少?存入多少?取出多少,目前能否 工作 大型连锁超市的老总也需要了解每一个分 店的经营状况。为糖果机增加一个位置属性 public class GumballMachine String location; public GumballMachine(String location, int count)
2、this.location = location; public String getLocation() return location; 糖果机监视器 为了将糖果机的状况向CEO汇报,我们设立 了糖果机监视器。可以形成一个报表public class GumballMonitorGumballMachine machine;public GumballMonitor(GumballMachine machine)this.machine = machine;public void report()System.out.println(“Gumball Machine:”+machine.g
3、etlocation(); 上述的糖果机监视器可以将糖果机的情况 汇报上来。 但是我们知道,一个企业的自动糖果机绝 不会是一台,且不会在一处,而是分散在 各地。 上述的监视器无法实现远程监控。糖果机糖果机监视器状态请求返回状态只可以在本地运行,共用一个JVM ,无法获取远程的糖果机的信息远程代理 远程代理:代理远程的对象的本地代表。 远程对象:不同机器上的对象。 本地代表:由本地方法调用的对象,结果 发送到远程对象。糖果监视器 代理糖果机糖果监视器 代理糖果机请求请求回应回应涉及RMI,如何进行远程方法调用糖果机例子 了解RMI 将GumballMachine变成远程服务,提供远 程调用的方法
4、 创建一个能和远程的GumballMachine沟通 的代理,这要用到RMI,结合监视系统。远程方法 当今的世界是网络的世界,基于网络的软 件系统非常流行。 基于网络的软件,有时一个对象需要和远 程的对象进行交互。ATM存取款刷卡消费 客户调用本地对象和客户调用远程对象有 何区别和联系客户本地对象网络远程对象客户调用本地和远程的对象方法不一致! 怎么办从被调用对象的角度看 被本地客户调用和被远程客户调用一样吗 ?本地客户可以直接调用,对象将结果直接返回 即可远程客户调用,对象需要通过网络将结果返回结论:本地客户调用和远程客户调用是不一致 的! 前面我们说过:我们不能让客户麻烦,还 需考虑所调用
5、的对象是在本地还是在远程 也不能给对象的编写带来额外的限制,还 需要给本地客户和远程客户提供两种不同 的接口。 那我们应该怎么做呢?大家想一想 当两个事物互相依赖,互相影响,耦合度 很高时,怎么解耦? 遇到这种情况,一个非常有效的办法就是 中间再加一个层次。客户对象 当两个事物互相依赖,互相影响,耦合度 很高时,怎么解耦? 遇到这种情况,一个非常有效的办法就是 中间再加一个层次。客户对象中介者 如果双方的差异度很大,需要多层客户对象中 介 1中 介 n比如网络传输协议,有七层协议,因为有时差异太大神舟七号,飞船的降落伞,有很多层 利用添加多个层次的方法来解耦的优缺点解耦两个对象可以独立并行开发
6、灵活可扩展增加了层次,造成传输的延迟,付出了时间代 价应用 以后如果遇到两个对象之间互相影响,耦 合度大时,考虑添加层次 如果系统实现难度很大,考虑多层次实现 。 前面我们所讲的模式,实际上都是可以用 这个思想解释。远程方法 在客户调用远程对象时,由于需要通过网 络,因此添加两个层次,可以让客户和远 程对象的开发不会因为需要通过网络而有 任何的改变。客户客 户 辅 助 对 象服 务 辅 助 对 象服务对象明星都有经纪人。从某种角度看,就是代理 。 有了两个辅助对象,客户调用本地对象和 远程对象的方法可以一致,客户不觉得, 但实际运行是不一致的;而服务被本地客 户调用和远程客户调用的方式也是一致
7、的 ,不需重新编写。Java RMI RMI提供了客户辅助对象和服务辅助对象 ,程序员可以不管网络的传输。Stub 桩 客户辅助对象Skeleton 骨架 服务辅助对象远程服务的制作 制作远程接口,定义出让客户调用的方法 制作远程的实现,为接口方法提供真正的 实现。 利用rmic产生stub和skeleton,rmic工具自 动处理 启动rmi注册表,客户可以查到代理的位置 开始远程服务,运行服务对象,注册到rmi 注册表,供客户调用。制作远程接口 扩展 java.rmi.Remote, Remote接口是一个记 号接口,不含有方法。public interface MyRemote exte
8、nds Remote 声明所有的方法会抛出异常 RemoteException,因 为网络调用,一切皆有可能,什么方法都有可能 出错。 import java.rmi.*;public interface MyRemote extends Remotepublic String sayHello() throws RemoteException; 制作远程接口(续) 确定变量和返回值是属于原语类型或是可 序列号类型。远程方法调用,必须将结果 打包通过网络进行传输。所以传送自己的 类必须能Serializable.public String sayHello() throws RemoteExc
9、eption;制作远程实现 服务必须实现远程接口,客户需要调用这个方法 。public class MyRemoteImpl extends UnicastRemoteObject implements MyRemotepublic String sayHello()return “Server says,Hay”; 需要远程功能,扩展 自父类,省很多工作设计构造器 public MyRemoteImpl() throws RemoteException 因为父类构造器会抛出一个异常,所以子 类也必须抛出一个异常 用RMI注册服务,有远程服务,可以被远 程客户调用。接着需要将服务实例化,加 入
10、注册表中。 try MyRemote service = new MyRemoteImpl(); Naming.rebind(“RemoteHello”,serice) catch(Exception ex).在RMI中注册名字和服务, 绑定服务对象时,RMI会把 服务换成Stub,因为它是客 户真正需要的。步骤三:产生stub和Skeleton JDK内置的工具rmic,用来产生桩和骨架 。如:rmic MyRemoteImpl.class Rmic就会产生两个类,分别是后缀 _stub.class 服务运行位置的主 机名或IP地址注册时用的名 字工作方式 客户到rmi的注册表中寻找代理 R
11、mi的注册表返回返回代理stub对象 客户调用stub方法,stub调用远程的服务 public class MyRemoteClient public static void mainString args) new MyRemoteClient().go(); public void go() try MyRemote service = (MyRemote)Naming.lookup(rmi:/127.0.0.1/RemoteHello ); String s = service.sayHello(); System.out.pringln(s); catch(Exception ex)
12、注意事项 启动远程服务之前必须先启动rmiregistry, 因为要是一其rebind注册服务 变量和值的类型是可序列化类型 必须预先提供stub类 客户端具有:client.class MyServiceImpl_Stub.class MyRemote.class 服务器端:MyServiceImpl.classMyServiceImpl_Stub.class MyServiceImpl_Skel.class MyRemote.class糖果机实例糖果机监视器糖果机桩骨架糖果机 需要把糖果机变成一个服务,可接收远程 访问的服务为糖果机创建一个远程接口,提供远程调用方 法确定接口方法的返回类型
13、是可序列化在一个具体的类中,实现了该接口。 public interface GumballMachineRemote extends Remote public int getCount() throws public String getLocation() throws public State getState() throws非序列化 Public interface State extends Serializable /投钱的状态 public void insertQuarter(); /退钱的状态 public void ejectQuarter(); /按下按纽状态 pub
14、lic void turnTrank(); /发放物品状态 public void dispense(); 根据前面所描述,状态类具有对象的引用 ,我们不可能把对象都传到远程,添加了 transient关键字。 public class NoQuarterState implements State transient GumballMachine gumballMachine; 不要序列化 糖果机服务的实现:见教材452代码在rmi注册表中进行注册 见教材453客户端实现 教材454测试代码public static void main(String args)String location
15、 = “rmi:/./gumballmachine”;“rmi:/. Gumballmachine”“rmi:/. Gumballmachine”GumballMonitor monitor = new GumballMonitorlocation.length;for(int i=0; igetIconWidth() getIconHeight() paintIcon()ImageIcongetIconWidth() getIconHeight() paintIcon()ImageProxygetIconWidth() getIconHeight() paintIcon()ImageProxy工作流程 首先创建一个ImageIcon,从网络上下载图 像 下载过程中,显示“C