1、代理(Proxy)模式部分
实现RMI(远程方法调用)的步骤:
[quote]---------------------------------------------------------------
一、定义远程服务接口,扩展java.rmi.Remote。
二、实现远程服务具体类,继承java.rmi.UnicastRemoteObject类。
三、利用rmic生成Stub和Skeleton类,在JDK5.0中使用了动态代理,不需要生成任何类。
四、启动RMI注册表(rmiregistry)。
五、启动远程服务,即将远程服务具体类注册到RMI注册表中。
六、调用远程服务。
---------------------------------------------------------------[/quote]
使用RMI常犯的三个错误:
[quote]---------------------------------------------------------------
一、忘了在启动远程服务之前先启动RMI注册表(要用Naming.rebind()注册服务,rmiregistry必须是运行的)。
二、忘了将变量和返回值的类型转为可序列化的类型(这种错误无法在编译期发现,只会在运行时发现)。
三、忘了给客户端提供Stub类。
---------------------------------------------------------------[/quote]
*transient关键字可以让JVM在序列化对象时忽略这个变量。
代理模式:为另一个对象提供替身或占位符以控制对这个对象的访问。
*使用代理模式创建代表(Representative)对象,让代表对象控制某对象的访问。被代理的对象可以是远程对象、创建开销大的对象或者需要安全控制的对象。
*远程代理是一般代理模式的一种实现。
代理模式有很多变种,几乎都与控制访问有关,它控制访问的几种方式:
[quote]---------------------------------------------------------------
一、远程代理控制远程对象的访问。
二、虚拟代理控制创建开销大的资源的访问。
三、保护代理基于权限控制对资源的访问。
---------------------------------------------------------------[/quote]
*远程代理(Remote Proxy)模式:可以作为另一个JVM上对象的本地代表。调用代理的方法会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果转给客户。
*虚拟代理(Virtual Proxy)模式:作为创建开销大的对象的代表。虚拟代理经常在我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由代理来扮演它的替身。对象创建后,代理就会将请求直接委托给对象。
设计谜题
---------------------------------------------------------------
使用第十章的状态(State)模式对ImageProxy类进行重新设计。
---------------------------------------------------------------
*动态代理:Java在java.lang.reflect包中有自己的代理支持。利用这个包你可以在运行时动态地创建代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。因为实际的代理类是在运行时创建的,因此称这项Java技术为动态代理。
NonOwnerInvocationHandler代码:
Sharpen your pencil解答:
连连看解答:
[quote]---------------------------------------------------------------
装饰者(Decorator)模式-->包装另一个对象,并提供额外的行为。
外观(Facade)模式-->包装许多对象以简化它们的接口。
代理(Proxy)模式-->包装另一个对象,并控制对它的访问。
适配器(Adapter)模式-->包装另一个对象,并提供不同的接口。
---------------------------------------------------------------[/quote]
其他种类的代理:
[quote]---------------------------------------------------------------
一、防火墙代理(Firewall Proxy):控制网络资源的访问,保护资源免受“坏客户”的侵害。
二、只能引用代理(Smart Reference Proxy):当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数。
三、缓存代理(Caching Proxy):为开销大的计算结果提供暂时存储。它允许多个客户共享结果以减少计算或网络延迟。
四、同步代理(Synchronization Proxy):在多线程的情况下为主题提供安全的访问。
五、复杂隐藏代理(Complexity Hiding Proxy):用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也成为外观代理(Facade Proxy)。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
六、写入时复制代理(Copy-On-Write Proxy):用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止,这是虚拟代理的变体。
---------------------------------------------------------------[/quote]
2、代理(Proxy)模式小结
*代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种。
*远程代理管理客户和远程对象之间的交互。
*虚拟代理控制访问实例化开销大的对象。
*保护模式基于调用者控制对对象方法的访问。
*代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理与写入时复制代理。
*代理在结构上类似装饰者,但是目的不同。
*装饰者模式为对象加上行为,而代理控制访问。
*Java内置的代理支持,可以根据需要动态创建代理,并将所有调用分配到所选的处理器。
*和其它的包装者(wrapper)一样,代理会造成你的设计中类的数目的增加。
3、RMI(远程方法调用)实例
4、远程代理(Remote Proxy)模式实例
测试结果:
[quote]The server is running...
The server is shutdown.[/quote]
5、虚拟代理(Virtual Proxy)模式实例(结合了状态模式)
测试结果:
[quote]Height:800,Width:600
The video is loading,please wait...
The video is loading,please wait...
The video is loading,please wait...
Video loaded.
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
Finished.
Height:800,Width:600[/quote]
6、保护代理(Protect Proxy)模式实例
测试结果:
[quote]User:Jim has been added.
User:Jimhas been updated.
Properties:
Age=28
Gender=male
--------------
User:Jimhas been deleted.
Can't add User!
User:Lilyhas been updated.
Properties:
Age=26
Gender=female
--------------
Can't delete User![/quote]
实现RMI(远程方法调用)的步骤:
[quote]---------------------------------------------------------------
一、定义远程服务接口,扩展java.rmi.Remote。
二、实现远程服务具体类,继承java.rmi.UnicastRemoteObject类。
三、利用rmic生成Stub和Skeleton类,在JDK5.0中使用了动态代理,不需要生成任何类。
四、启动RMI注册表(rmiregistry)。
五、启动远程服务,即将远程服务具体类注册到RMI注册表中。
六、调用远程服务。
---------------------------------------------------------------[/quote]
使用RMI常犯的三个错误:
[quote]---------------------------------------------------------------
一、忘了在启动远程服务之前先启动RMI注册表(要用Naming.rebind()注册服务,rmiregistry必须是运行的)。
二、忘了将变量和返回值的类型转为可序列化的类型(这种错误无法在编译期发现,只会在运行时发现)。
三、忘了给客户端提供Stub类。
---------------------------------------------------------------[/quote]
*transient关键字可以让JVM在序列化对象时忽略这个变量。
代理模式:为另一个对象提供替身或占位符以控制对这个对象的访问。
*使用代理模式创建代表(Representative)对象,让代表对象控制某对象的访问。被代理的对象可以是远程对象、创建开销大的对象或者需要安全控制的对象。
*远程代理是一般代理模式的一种实现。
代理模式有很多变种,几乎都与控制访问有关,它控制访问的几种方式:
[quote]---------------------------------------------------------------
一、远程代理控制远程对象的访问。
二、虚拟代理控制创建开销大的资源的访问。
三、保护代理基于权限控制对资源的访问。
---------------------------------------------------------------[/quote]
*远程代理(Remote Proxy)模式:可以作为另一个JVM上对象的本地代表。调用代理的方法会被代理利用网络转发到远程执行,并且结果会通过网络返回给代理,再由代理将结果转给客户。
*虚拟代理(Virtual Proxy)模式:作为创建开销大的对象的代表。虚拟代理经常在我们真正需要一个对象的时候才创建它。当对象在创建前和创建中时,由代理来扮演它的替身。对象创建后,代理就会将请求直接委托给对象。
设计谜题
---------------------------------------------------------------
使用第十章的状态(State)模式对ImageProxy类进行重新设计。
---------------------------------------------------------------
*动态代理:Java在java.lang.reflect包中有自己的代理支持。利用这个包你可以在运行时动态地创建代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。因为实际的代理类是在运行时创建的,因此称这项Java技术为动态代理。
NonOwnerInvocationHandler代码:
---------------------------------------------------------------
import java.lang.reflect.*;
public class NonOwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public NonOwnerInvocationHandler(PersonBean person){
this.person = person;
}
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException{
try{
if(method.getName().startsWith("get")){
return method.invoke(person,args);
}else if(method.getName().equals("setHotOrNotRating")){
return method.invoke(person,args);
}else if(method.getName().startsWith("set")){
throw new IllegalAccessException();
}
} catch (InvocationTargetException e){
e.printStackTrace();
}
return null;
}
}
---------------------------------------------------------------
Sharpen your pencil解答:
---------------------------------------------------------------
PersonBean getNonOwnerProxy(PersonBean person){
return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new NonOwnerInvocationHandler());
}
PersonBean getProxy(PersonBean person,InvocationHandler handler){
if(handler instanceof OwnerInvocationHandler){
return getOwnerProxy(person);
}else if(handler instanceof NonOwnerInvocationHandler){
return getNonOwnerProxy(person);
}
}
---------------------------------------------------------------
连连看解答:
[quote]---------------------------------------------------------------
装饰者(Decorator)模式-->包装另一个对象,并提供额外的行为。
外观(Facade)模式-->包装许多对象以简化它们的接口。
代理(Proxy)模式-->包装另一个对象,并控制对它的访问。
适配器(Adapter)模式-->包装另一个对象,并提供不同的接口。
---------------------------------------------------------------[/quote]
其他种类的代理:
[quote]---------------------------------------------------------------
一、防火墙代理(Firewall Proxy):控制网络资源的访问,保护资源免受“坏客户”的侵害。
二、只能引用代理(Smart Reference Proxy):当主题被引用时,进行额外的动作,例如计算一个对象被引用的次数。
三、缓存代理(Caching Proxy):为开销大的计算结果提供暂时存储。它允许多个客户共享结果以减少计算或网络延迟。
四、同步代理(Synchronization Proxy):在多线程的情况下为主题提供安全的访问。
五、复杂隐藏代理(Complexity Hiding Proxy):用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也成为外观代理(Facade Proxy)。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
六、写入时复制代理(Copy-On-Write Proxy):用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止,这是虚拟代理的变体。
---------------------------------------------------------------[/quote]
2、代理(Proxy)模式小结
*代理模式为另一个对象提供代表,以便控制客户对对象的访问,管理访问的方式有许多种。
*远程代理管理客户和远程对象之间的交互。
*虚拟代理控制访问实例化开销大的对象。
*保护模式基于调用者控制对对象方法的访问。
*代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理与写入时复制代理。
*代理在结构上类似装饰者,但是目的不同。
*装饰者模式为对象加上行为,而代理控制访问。
*Java内置的代理支持,可以根据需要动态创建代理,并将所有调用分配到所选的处理器。
*和其它的包装者(wrapper)一样,代理会造成你的设计中类的数目的增加。
3、RMI(远程方法调用)实例
/**
* 远程接口
*
* @author zangweiren 2010-4-8
*
*/
public interface HelloRemote extends Remote {
String sayHello() throws RemoteException;
}
/**
* 远程服务实现类
*
* @author zangweiren 2010-4-8
*
*/
public class HelloImpl extends UnicastRemoteObject implements HelloRemote {
private static final long serialVersionUID = -5554845400316615009L;
public static void main(String[] args) {
try {
HelloRemote helloRemote = new HelloImpl();
Naming.rebind("HelloRemote", helloRemote);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public HelloImpl() throws RemoteException {
}
@Override
public String sayHello() throws RemoteException {
return "Hello,world.I am zangweiren.";
}
}
/**
* 远程服务客户端
*
* @author zangweiren 2010-4-8
*
*/
public class HelloClient {
public static void main(String[] args) {
try {
HelloRemote helloRemote = (HelloRemote) Naming
.lookup("rmi://127.0.0.1/HelloRemote");
String words = helloRemote.sayHello();
System.out.println(words);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
4、远程代理(Remote Proxy)模式实例
/**
* 服务器远程接口
*
* @author zangweiren 2010-4-8
*
*/
public interface ServerRemote extends Remote {
void shutdown() throws RemoteException;
void startup() throws RemoteException;
}
/**
* 服务器实现类
*
* @author zangweiren 2010-4-8
*
*/
public class ServerImpl extends UnicastRemoteObject implements ServerRemote {
private static final long serialVersionUID = -1466325816915299894L;
public static void main(String[] args) {
ServerRemote server;
try {
server = new ServerImpl();
Naming.rebind("ServerRemote", server);
} catch (RemoteException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public ServerImpl() throws RemoteException {
}
@Override
public void shutdown() throws RemoteException {
System.out.println("The server is shutdown.");
}
@Override
public void startup() throws RemoteException {
System.out.println("The server is running...");
}
}
/**
* 远程代理客户端测试程序
*
* @author zangweiren 2010-4-8
*
*/
public class TestServer {
public static void main(String[] args) {
try {
ServerRemote server = (ServerRemote) Naming.lookup("ServerRemote");
server.startup();
server.shutdown();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
}
}
测试结果:
[quote]The server is running...
The server is shutdown.[/quote]
5、虚拟代理(Virtual Proxy)模式实例(结合了状态模式)
/**
* 视频播放器
*
* @author zangweiren 2010-4-8
*
*/
public interface MediaPlayer {
int getHeight();
int getWidth();
void play();
}
/**
* 视频播放器实现类
*
* @author zangweiren 2010-4-8
*
*/
public class MediaPlayerImpl implements MediaPlayer {
@Override
public int getHeight() {
return 1024;
}
@Override
public int getWidth() {
return 768;
}
@Override
public void play() {
System.out.println("The vedio is playing...");
}
}
/**
* 视频播放器状态
*
* @author zangweiren 2010-4-8
*
*/
public interface MediaPlayerState extends MediaPlayer {
}
/**
* 未加载状态
*
* @author zangweiren 2010-4-8
*
*/
public class NotLoadedState implements MediaPlayerState {
private MediaPlayerProxy player;
public NotLoadedState(MediaPlayerProxy player) {
this.player = player;
}
@Override
public int getHeight() {
return 800;
}
@Override
public int getWidth() {
return 600;
}
@Override
public void play() {
player.setState(player.getLoadingState());
player.play();
}
}
/**
* 加载中状态
*
* @author zangweiren 2010-4-8
*
*/
public class LoadingState implements MediaPlayerState {
private MediaPlayerProxy player;
public LoadingState(MediaPlayerProxy player) {
this.player = player;
}
@Override
public int getHeight() {
return 800;
}
@Override
public int getWidth() {
return 600;
}
@Override
public void play() {
for (int i = 0; i < 3; i++) {
System.out.println("The video is loading,please wait...");
}
System.out.println("Video loaded.");
player.setState(player.getLoadedState());
player.play();
}
}
/**
* 已加载状态
*
* @author zangweiren 2010-4-8
*
*/
public class LoadedState implements MediaPlayerState {
private MediaPlayerProxy player;
public LoadedState(MediaPlayerProxy player) {
this.player = player;
}
@Override
public int getHeight() {
return 1024;
}
@Override
public int getWidth() {
return 768;
}
@Override
public void play() {
for (int i = 0; i < 5; i++) {
System.out.println("The video is playing...Height:"
+ player.getHeight() + ",Width:" + player.getWidth());
}
System.out.println("Finished.");
player.setState(player.getNotLoadedState());
}
}
/**
* 视频播放器代理类
*
* @author zangweiren 2010-4-8
*
*/
public class MediaPlayerProxy implements MediaPlayer {
private MediaPlayerState notLoaded;
private MediaPlayerState loading;
private MediaPlayerState loaded;
private MediaPlayerState state;
public MediaPlayerProxy() {
notLoaded = new NotLoadedState(this);
loading = new LoadingState(this);
loaded = new LoadedState(this);
state = notLoaded;
}
@Override
public int getHeight() {
return state.getHeight();
}
public MediaPlayerState getLoadedState() {
return loaded;
}
public MediaPlayerState getLoadingState() {
return loading;
}
public MediaPlayerState getNotLoadedState() {
return notLoaded;
}
public MediaPlayerState getState() {
return state;
}
@Override
public int getWidth() {
return state.getWidth();
}
@Override
public void play() {
state.play();
}
public void setState(MediaPlayerState state) {
this.state = state;
}
}
测试程序:
/**
* 视频播放器测试程序
*
* @author zangweiren 2010-4-8
*
*/
public class TestMediaPlayer {
public static void main(String[] args) {
MediaPlayer player = new MediaPlayerProxy();
System.out.println("Height:" + player.getHeight() + ",Width:"
+ player.getWidth());
player.play();
System.out.println("Height:" + player.getHeight() + ",Width:"
+ player.getWidth());
}
}
测试结果:
[quote]Height:800,Width:600
The video is loading,please wait...
The video is loading,please wait...
The video is loading,please wait...
Video loaded.
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
The video is playing...Height:1024,Width:768
Finished.
Height:800,Width:600[/quote]
6、保护代理(Protect Proxy)模式实例
/**
* 用户管理类接口
*
* @author zangweiren 2010-4-8
*
*/
public interface UserManager {
public abstract void addUser(String name);
public abstract void deleteUser(String name);
public abstract void updateUser(String name,
HashMap<String, String> properties);
}
/**
* 用户管理类
*
* @author zangweiren 2010-4-8
*
*/
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String name) {
System.out.println("User:" + name + " has been added.");
}
@Override
public void deleteUser(String name) {
System.out.println("User:" + name + "has been deleted.");
}
@Override
public void updateUser(String name, HashMap<String, String> properties) {
System.out.println("User:" + name + "has been updated.");
System.out.println("Properties:");
Iterator<String> keys = properties.keySet().iterator();
String key;
while (keys.hasNext()) {
key = keys.next();
System.out.println(key + "=" + properties.get(key));
}
System.out.println("--------------");
}
}
/**
* 管理员处理类
*
* @author zangweiren 2010-4-8
*
*/
public class AdminInvocationHandler implements InvocationHandler {
private UserManager manager;
public AdminInvocationHandler(UserManager manager) {
this.manager = manager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {
try {
if (method.getName().equals("addUser")) {
return method.invoke(manager, args);
} else if (method.getName().equals("updateUser")) {
return method.invoke(manager, args);
} else if (method.getName().equals("deleteUser")) {
return method.invoke(manager, args);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 普通用户处理类
*
* @author zangweiren 2010-4-8
*
*/
public class UserInvocationHandler implements InvocationHandler {
private UserManager manager;
public UserInvocationHandler(UserManager manager) {
this.manager = manager;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws IllegalAccessException {
try {
if (method.getName().equals("addUser")) {
throw new IllegalAccessException();
} else if (method.getName().equals("updateUser")) {
return method.invoke(manager, args);
} else if (method.getName().equals("deleteUser")) {
throw new IllegalAccessException();
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 工具类
*
* @author zangweiren 2010-4-8
*
*/
public class UserManagerUtils {
public static UserManager getAdminProxy(UserManager manager) {
return (UserManager) Proxy.newProxyInstance(manager.getClass()
.getClassLoader(), manager.getClass().getInterfaces(),
new AdminInvocationHandler(manager));
}
public static UserManager getUserProxy(UserManager manager) {
return (UserManager) Proxy.newProxyInstance(manager.getClass()
.getClassLoader(), manager.getClass().getInterfaces(),
new UserInvocationHandler(manager));
}
}
/**
* 测试类
*
* @author zangweiren 2010-4-8
*
*/
public class TestUserManager {
public static void main(String[] args) {
UserManager manager = new UserManagerImpl();
UserManager admin = UserManagerUtils.getAdminProxy(manager);
admin.addUser("Jim");
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("Gender", "male");
properties.put("Age", "28");
admin.updateUser("Jim", properties);
admin.deleteUser("Jim");
System.out.println();
UserManager user = UserManagerUtils.getUserProxy(manager);
try {
user.addUser("Lily");
} catch (Exception e) {
System.out.println("Can't add User!");
}
properties = new HashMap<String, String>();
properties.put("Gender", "female");
properties.put("Age", "26");
user.updateUser("Lily", properties);
try {
user.deleteUser("Lily");
} catch (Exception e) {
System.out.println("Can't delete User!");
}
}
}
测试结果:
[quote]User:Jim has been added.
User:Jimhas been updated.
Properties:
Age=28
Gender=male
--------------
User:Jimhas been deleted.
Can't add User!
User:Lilyhas been updated.
Properties:
Age=26
Gender=female
--------------
Can't delete User![/quote]