- 浏览: 410794 次
- 性别:
- 来自: 秦皇岛
-
最新评论
-
prayjourney:
了解了,讲的不错
DataInputStream和DataOutputStream类 -
niunianss:
将字节退回的时候,需要添加判断,最后一个字符是英文时,实际数组 ...
PushbackInputStream -
cctt_1:
不要误人子弟,那根本就不是 解释器模式!!!那是Composi ...
Interpreter(解释器)模式 -
java-大神:
[i][i]引用引用引用引用[/img][/img][/img ...
BufferedReader和BufferedWriter -
百合不是茶:
你的程序在文件输入输出流中传入agrs[0]时,会报错越界 ...
DataInputStream和DataOutputStream类
2. 重新思考图像代理:
现在需要思考设计模式是否真的能够帮助我们。之前我们费尽心血实现了一个设计模式,而现在又要考虑将它拆掉。现实的开发中会遇到更多这样的情况,实际上这是很自然的。经过他人的评审之后,设计人员可以在发布之前重新构思自己的设计,并修改其中有问题的部分。在实际过程中,设计模式可以帮助我们设计和调试应用程序,另外也方便了他人对我们的设计进行讨论。就Oozinoz公司的ImageIconProxy类而言,模式也起到了自己的作用,虽然不实现Proxy模式会更简单。
ImageIcon类操控Image对象。如果不把绘图请求转发给单独的ImageIcon对象,而是直接操作ImageIcon中的Image对象,这样会更简单。下图显示的LoadingImageIcon位于com.oozinoz.imaging包中;除了构造器,该类仅提供两个方法:load()方法和run()方法。
LoadingImageIcon类的作用是切换Image对象
对该类进行修改后,其load()方法仍然以JFrame对象为参数,用于在指定图像加载完毕之后进行回调。在执行load()方法的时候,它先以LOADING引用的图像对象为参数调用setImage()方法,然后重新绘制图形显示窗口,最后为自己启动一个单独的线程。而run()方法是在单独的线程中执行的,该方法根据构造器中指定的图像文件名创建一个新的ImageIcon对象,然后以该图像对象为参数调用setImage()方法,最后重绘该窗口。
突破题:请填写完整下面LoadingImageIcon类的load()方法和run()方法。
package com.oozinoz.imaging; import javax.swing.ImageIcon; import javax.swing.JFrame; public class LoadingImageIcon extends ImageIcon implements Runnable { static final ImageIcon ABSENT = new ImageIcon(ClassLoader.getSystemResource("images/absent.jpg"); static final ImageIcon LOADING = new ImageIcon (ClassLoader.getSystemResource("images/loading.jpg); protected String filename; protected String callbackFrame; public LoadingImageIcon(String filename) { super(ABSENT.getImage()); this.filename = filename; } public void load(JFrame callbackFrame) { this.callbackFrame = callbackFrame; setImage(LOADING.getImage()); callbackFrame.repaint(); new Thread(this).start(); } public void run() { setImage(new ImageIcon(ClassLoader.getSystemResource(filename)).getImage()); callbackFrame.pack(); } }
其中load()方法将当前图像设置成"Loading...",而run()方法是在另一个线程中执行,它负责加载指定的图像。
修改后的代码与ImageIcon设计的耦合就不那么紧了;现在的代码主要依赖ImageIcon类的getImage()方法和setImage()方法,而不再依赖请求转发机制。实际上,现在根本不存在转发:LoadingImageIcon类虽然在结构上不是代理,但却起着代理的作用。
依赖于转发的Proxy模式会造成维护方面的负担。例如,随着底层对象的变化,Oozinoz公司将不得不更新代理。为了避免这种开销,我们应该经常考虑Proxy模式的替代方案,但是Proxy模式仍然可能是正确的选择。特别是在我们需要获取消息的对象正在另一台机器上执行的时候,Proxy模式可能不存在替代方案。
3. 远程代理:
如果我们期望调用正在另一台计算机上运行的对象的方法,那么必须找到一种方法来与该远程对象通信,而不能直接调用其方法。我们可以在远程机器上打开一个套接字,并设计一种协议用于向远程对象发送消息。理想情况下,这种方案可以让我们自由地与远程对象通信,就像与本地对象通信一样。在这种方案下使用Proxy模式,可直接调用位于本地的代理对象的方法,该代理对象将调用请求发给远程对象。实际上,著名的公共请求代理架构(CORBA)、ASP.NET以及Java的远程方法调用(RMI)已经实现了这种方案。
在RMI中,代理对象用于将调用请求转发给在另一台计算机上运行的指定对象,客户可以很容易地获得这种代理对象。企业JavaBeans(EJB)规范是业界新兴的一个重要标准,它的基础之一便是RMI;要理解EJB,必须先了解RMI。无论业界标准如何发展,我们可以预见未来的分布计算仍将离不开Proxy模式。RMI为代理模式的实践提供了一个很好的例子。
我们期望能够通过下面的这个RMI应用程序例子,向读者说明其中的Proxy模式如何应用以及该模式的价值所在,而不只是简单介绍一下RMI的使用。RMI和EJB带来了许多新的设计理念;我们不能简单地使所有对象都变成远程的以得到一个合理的系统。但这方面将不作深入讨论,而只是简单探究一下RMI对于Proxy模式来说到底是怎么重要的一个例子。
下面的这个例子中,我们利用RMI让另一台计算机上的Java程序访问一个对象的方法,以此来探究RMI的工作机制。开发的第一步是为指定的远程对象创建一个接口。作为一个实验性的项目,我们为Oozinoz公司创建了一个Rocket接口,该接口独立于Oozinoz公司的现有代码:
package com.oozinoz.remote; import java.rmi.*; public interface Rocket extends Remote { void boost(double factor) throws RemoteException; double getApogee() throws RemoteException; double getPrice() throws RemoteException; }
Rocket接口扩展了Remote接口。该接口中的所有方法都声明自己会抛出RemoteException异常对象。作为服务的提供者,远程对象不仅实现了远程接口,还要扩展UnicastRemoteObject类,如下图所示:
若要使用RMI,首先要创建一个远程接口,定义需要在计算机之间 交互的消息,
再创建一个远程对象;该远程对象可实现远程接口,并扩展UnicastRemotObject类
RocketImpl对象作为服务提供者类运行在服务器上,客户端可以通过运行在本地的代理对象来访问RocketImpl对象的方法。RocketImpl类的代码比较简单:
package com.oozinoz.remote; import java.rmi.*; import java.rmi.server.UnicastRemoteObject; public class RocketImpl extends UnicastRemoteObject implements Rocket { protected double price; protected double apogee; public RocketImpl(double price,double apogee) throws RemoteException { this.price=price; this.apogee=apogee; } public void boost(double factor) { apogee=factor; } public double getApogee() { return apogee; } public double getPrice() { return price; } }
RocketImpl的实例运行在一台机器上,我们要让它能够被运行在其他机器上的Java程序访问,就必须在客户端为RocketImpl对象提供一个代理对象。为了实现此目的,客户端需要一个RocketImpl对象的代理。该代理类必须实现Rocket接口,并且提供用于与远程对象通信的附加特性。RMI的最大便利之一就是它能够自动创建这个代理类。为了自动生成代理类,我们必须把RocketImpl.java文件和Rocket.java接口文件存放在RMI注册程序的运行目录之下:
package com.oozinoz.remote; import java.rmi.*; public class RegisterRocket { public static void main(String[] args) { try{ Rocket biggie = new RocketImpl(29.95,820);//可以将biggie声明为RocketImpl类。不过重要的是,只要biggie实现了Rocket接口,它就可以被用户查询到。 Naming.rebind("rmi://localhost:5000/Biggie",biggie); }catch(Exception e){ e.printStackTrace(); } } }
D:\rmi>dir /b com\oozinoz\remote
RegisterRocket.class
RegisterRocket.java
Rocket.class
Rocket.java
RocketImpl.class
RocketImpl.java
ShowRocketClient.class
ShowRocketClient.java
运行JDK提供的RMI编译器,自动生成用于简化远程通信的RocketImpl存根。
D:\rmi>rmic com.oozinoz.remote.RocketImpl
值得注意的是,rimc命令以完整的类名而不是文件名作为参数。早期版本号的JDK将用于客户端的部分和用于服务器端的部分分别存放在不同的文件中。从版本1。2起,RMI编译器将用于客户端和服务器端的部分都存放在一个独立的存根文件中。rimc命令编译了它所需要的所有类,并创建了RocketImpl_Stub类:
D:\rmi>dir /b com\oozinoz\remote
RegisterRocket.class
RegisterRocket.java
Rocket.class
Rocket.java
RocketImpl.class
RocketImpl.java
RocketImpl_Stub.class
ShowRocketClient.class
ShowRocketClient.java
在对象能够被远程访问之前,我们必须用运行在服务器上的RMI注册程序注册该对象。rmiregistry可执行程序是JDK的一部分。在运行注册程序的时候,需指定注册程序所监听的端口:
D:\rmi>rmiregistry 5000
在服务器上运行了注册程序之后,我们便可以开始创建和注册RocketImpl对象:
当编译并运行该代码后,该程序会显示出对象注册成功的确认信息。
Registered biggie
运行RegisterRocket应用程序便可在服务器上创建并运行一个RocketImpl对象biggie。客户端只要能够访问Rocket接口和RocketImpl_Stub类,便可以访问远程运行的biggie对象。如果只有一台机器,我们仍然可以测试这个RMI应用程序,不过要在localhost而不是另外一台机器上运行服务器端代码:
package com.oozinoz.remote; import java.rmi.*; public class ShowRocketClient { try{ Object obj = Naming.lookup("rmi://localhost:5000/Biggie"); Rocket biggie = (Rocket)obj; System.out.println("Apogee is "+biggie.getApogee()); }catch(Exception e){ System.out.println("Exception while looking up a rocket;"); e.printStackTrace(); } }
当这个程序运行的时候,它首先使用注册名"Biggie"来查找远程对象。该远程对象代表着远程的一个RocketImpl对象;lookup()方法返回的对象obj是RocketImpl_Stub类的一个实例。RocketImpl_Stub类实现了Rocket接口,因而我们可以将对象obj强制转化为Rocket接口的一个对象。RocketImpl_Stub类继承了RemoteStub类,使其对象能够与服务器通信。
运行ShowRocketClient程序时,屏幕上将显示"Biggie"火箭的最高距离数据:
Apogee is 820.0
对代理对象getApogee()方法的调用将会转发给运行在服务器上的Rocket接口的实现对象。
突破题:下图显示getApogee()方法被转发的过程。最右边的对象使用粗体方框加以标识,表明它与ShowRocketClient程序分别运行在不同的机器上。请填写图中空缺的类名。
基于RMI的分布式应用程序的消息流
RMI的优点在于它使得客户端程序只需与本地代理对象进行交互便可达到与远程对象通信的目的。RMI用户定义了客户端和服务器端共享对象的接口。RMI为客户端和服务器端分别提供一个Rocket接口的实现类;这两个类实现相互协作,从而可完成进程间的无缝通信。服务器端和客户端则不必关心这些细节。
自己总结:这里ShowRocketClient在实际应用中处于客户端,此应用程序访问本地(即客户端)对象RocketImpl_Stub的getApogee()方法,但RocketImpl_Stub将此方法转发给了远程的RocketImpl对象。应该是RocketImpl_Stub类和ShowRocketCient应用程序存放在客户端,RegisterRocket、Rocket及RocketImpl类都位于服务器端。
发表评论
-
内部类总结
2009-11-27 14:28 1240一、方法及作用域内的内部类:1.在一个方法内定义的类2.在一个 ... -
finalize()方法终结条件验证 示例代码
2009-09-20 09:23 1371package Initialization; clas ... -
Junit简介
2009-04-08 17:46 16701. 单元测试(Unit Test) 一个单元(Un ... -
Ant简介
2009-04-08 13:10 18781. Ant可以自动完成的任务: (1)编译Java源代 ... -
专题制作--文字编辑器(文字编辑与保存)
2009-04-08 10:43 22411. 文字编辑与保存: (1). 打开文件的处理流 ... -
专题制作--文字编辑器(逻辑实现部分)
2009-04-07 22:35 19251. 事件处理: 在Java中事件以具体的对象来表 ... -
专题制作--文字编辑器(接口部分)
2009-04-07 20:28 21631. Swing入门: 若要使用J2SE来开发窗口应用 ... -
信息绑定(国际化处理)
2009-04-07 20:02 16051. 程序中的一些文字信息可以将之定义在一个属性文件中,而不定 ... -
日志(Logging)
2009-04-07 16:14 17621. 日志(Logging) 程序不免会出现错误,当 ... -
Java中的日期和时间
2009-04-07 11:26 19651. 使用Date: 使用System.cu ... -
meta-annotation
2009-04-07 09:23 30951. 所谓meta-annotation就是Annotati ... -
Annotion
2009-04-06 23:05 17011. Annotation对程序运行没有影响,它的目的在于对编 ... -
使用反射生成与操作对象(二)
2009-04-06 17:04 17631. 修改成员值: 尽管直接存取类的域成员是不被鼓励的 ... -
使用反射生成与操作对象(一)
2009-04-06 15:16 21331. 使用反射机制,可以在运行时期动态加载类并生成对象,操作对 ... -
Java中的反射(二)
2009-04-06 10:42 20941. 当在命令行模式下执行java XXX.class 指令后 ... -
Java中的反射(一)
2009-04-06 09:43 14091. Java提供的反射机制允许您在运行时动态加载类、查看类信 ... -
容器类的线程安全及ThreadLocal类
2009-04-05 21:28 30731. 容器类默认没有考虑 ... -
wait()和notify()
2009-04-05 19:06 13891. wait()、notify()、notifyAll() ... -
Java线程之同步化(Synchronized)主题
2009-04-05 16:44 27231. 如果一个对象所持有的数据可以被多线程同时共享存取,必须 ... -
Java线程(三)
2009-04-05 15:37 18961. Java中的每个线程都 ...
相关推荐
Proxy代理模式是面向对象设计模式中的重要组成部分,它在软件工程中扮演着关键角色,尤其在Java编程中。代理模式的主要目的是为一个对象提供一个替身或者占位符,以便控制对这个对象的访问。这种设计模式允许我们...
2. **远程代理**:这种代理模式用于处理远程对象,例如在网络上的对象,通过代理对象在本地进行操作,隐藏了远程调用的复杂性。 3. **安全代理**:用于控制对象访问权限,只有经过授权的代理对象才能访问真实对象。...
Proxy代理模式是设计模式中的一种,它在Java中扮演着重要的角色,特别是在处理远程调用、安全性、缓存以及日志记录等方面。代理模式的基本思想是为一个对象提供一个替身或者占位符,以便控制对这个对象的访问。在这...
**设计模式之代理模式(Proxy Pattern)** 设计模式是软件工程中的一种最佳实践,它是在特定情境下解决常见问题的模板。代理模式是其中一种行为设计模式,它的核心思想是为一个对象提供一个替身或者代理,以控制对...
代理模式是一种常用的设计模式,它在软件开发中扮演着重要的角色。代理模式允许我们为一个对象创建一个代理,这个代理对象在客户端和目标对象之间起到中介的作用,可以增强或控制对目标对象的访问。代理模式的主要...
综上所述,Proxy代理模式是设计模式中的一个重要组成部分,它允许我们在不改变原始对象的情况下,通过代理对象实现对原始对象的控制和扩展。在Java中,通过Java的Proxy类和InvocationHandler接口,我们可以轻松地...
### C#面向对象设计模式纵横谈(13):Proxy 代理模式(结构型模式) #### 重要概念:代理模式 代理模式是一种常用的结构型设计模式,它通过为另一个对象提供一个代理,来控制对该对象的访问。这种模式在软件工程中...
代理模式是设计模式中的一种结构型模式,它在对象交互中起到了中介的作用,允许通过代理对象来控制对原对象的访问。代理模式的核心思想是为一个对象提供一个替身,以便增加新的功能或者控制对原对象的访问。这种模式...
2. **代理模式的角色**: - **真实对象(Real Subject)**:这是代理模式所代理的实际业务对象,它实现了与代理对象相同的接口,以便代理对象可以调用真实对象的方法。 - **代理对象(Proxy)**:代理对象持有对...
代理模式是一种设计模式,属于结构型模式之一,其主要目的是为其他对象提供一个代理,以控制对该对象的访问。在实际应用中,代理模式能够帮助我们实现如下的功能: 1. 远程代理:代理对象可以代表一个位于远程系统...
代理模式是设计模式的一种,它的主要目的是在不改变原有对象的基础上,为一个对象提供额外的功能或者控制对这个对象的访问。在Android开发中,代理模式的应用尤为常见,尤其在处理复杂的业务逻辑、网络请求、界面...
Proxy Pattern 代理模式 采用JAVA实现,可以下载看看。
2. **JDK动态代理**:Java的`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口提供了动态生成代理对象的能力。在运行时,我们可以根据接口创建代理对象,而无需预先编写代理类。`...
这里我们探讨的“spring proxy代理模仿”主要指的是Spring AOP(面向切面编程)中的动态代理实现。Spring AOP通过代理模式为我们提供了在运行时向目标对象添加拦截器或切面的能力,这在进行日志记录、性能监控、事务...
JDBC代理主要涉及两个技术领域:AOP(面向切面编程)和设计模式中的代理模式。 【描述】:“代码对应的blog:http://blog.csdn.net/keyboardsun/archive/2008/01/30/2072865.aspx” 这个博客文章详细介绍了如何...
这个"proxy.rar"压缩包中包含了这三种代理模式的源代码示例,以及对泛型的应用。 1. 静态代理: 静态代理是最基础的代理形式,它通过创建一个代理类来实现目标接口,并在代理类中调用目标对象的方法。这种方式需要...
代理模式(Proxy Pattern)是一种结构型设计模式,用于为其他对象提供一种代理以控制对这个对象的访问。代理模式通常用于保护、延迟加载、记录请求等场景,可以在不改变原有对象的情况下为其增加新的功能。 代理...
代理模式是一种设计模式,它允许我们为一个对象创建一个代理对象,这个代理对象在客户端和目标对象之间起到中介的作用,可以实现额外的功能,比如监控、权限控制、事务管理等,而客户端无需关心这些细节。...
在这些模式中,代理模式(Proxy Pattern)是一种常用的结构型设计模式,它允许我们为一个对象创建一个代理,该代理对象在客户端和目标对象之间起到中介的作用,可以增加额外的功能或控制访问。 代理模式分为两种...