设计模式
代理模式:为还有一个对象提供一个替身或占位符以控制对这个对象的訪问。
使用代理模式创建代表对象,让代表对象控制某对象的訪问,被代理的对象能够使远程的对象(远程代理)、创建开销大的对象(虚拟代理),或须要安全控制的对象(保护代理)。
远程代理:能够作为还有一个JVM上对象的本地代表。
调用代理的方法,会被代理利用网络转发到远程运行,而且结果会通过网络返回给代理。再由代理将结果返回给客户。
虚拟代理:作为创建开销大的对象的代表。
虚拟代理常常直到我们真正须要一个对象的时候才创建它。
当对象在创建前和创建中时。由虚拟代理来扮演对象的替身。对象创建后代理就会将请求直接托付给对象。
动态代理:java在java.lang.reflect包中有自己的代理支持,利用这个包你能够在执行时动态的创建一个代理类,实现一个或多个接口,并将方法的调用转发到你所指定的类。
实际的代理类是在执行时创建的,在Java中我们称这样的技术为动态代理。
利用Java的动态代理。能够实现保护代理。
防火墙代理:控制网络资源的訪问,保护主题免于“坏客户”的侵害。
智能引用代理:当主题被引用时,进行额外的动作,比如计算一个对象被引用的次数。
缓存代理:为开销大的运算结果提供临时存储,它也执行多个客户共享结果。以降低计算或网络延迟。
同步代理:多线程的情况下为主题提供安全的訪问。
复杂隐藏代理:用来隐藏一个类的复杂集合的复杂度。并进行訪问控制。有时候也成为外观代理。复杂隐藏代理和外观模式不一样,由于代理控制訪问,而外观模式仅仅是提供还有一组接口。
写入时复制代理:用来控制对象的复制,方法是延迟对象的复制,知道客户真正须要为止,这是虚拟代理的变体。
制作远程服务
(1)制作远程接口
(2)制作远程实现
(3)利用rmic产生stub和skeleton
(4)启动RMI registry
(5)開始远程服务
设计原则
封装变化
多用组合。少用继承
针对接口编程,不针对实现编程
为交互对象之间的送耦合设计而努力
类应该对扩展开发,对改动关闭
依赖抽象,而不依赖详细类
仅仅和朋友交谈
别找我。我会找你
类应该仅仅有一个改变的理由
要点
代理在结构上类似装饰者。可是目的不一样。装饰者模式为对象加上行为。而代理则是控制行为。
和其它包装者一样,代理会造成你的设计中类的数目添加。
远程代理
import java.rmi.Remote;//用来做rmiregistry lookup的naming类在java.rmi包中 import java.rmi.RemoteException; //extends Remote这表示此接口要用来支持远程调用 public interface GumballMachineRemote extends Remote { //准备支持的方法,每一个都要抛出RemoteException //由于每次远程方法调用都必须考虑成“有风险的” public int getCount() throws RemoteException; public String getLocation() throws RemoteException; //返回值将从server经过网络运回客户。所以必须是原语类型或可序列化类型 public State getState() throws RemoteException; } //扩展Serializable接口。使得State可序列化 public interface State extends Serializable { public void insertQuarter(); public void ejectQuarter(); public void turnCrank(); public void dispense(); } public class HasQuarterState implements State { private static final long serialVersionUID = 768887299984514010L; Random randomWinner = new Random(System.currentTimeMillis()); //对于State的每一个市县。我们都在GumballMachine实例变量前面加上transientkeyword,这样就能够高考JVM不要序列化这个字段 transient GumballMachine gumballMachine; //其它方法 } //GumballMachine 要继承UnicastRemoteObject成为一个远程服务 //GumballMachine 也须要实现GumballMachineRemote这个远程接口 public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote { /** * */ private static final long serialVersionUID = -2838970117227273571L; State soldOutState; State noQuarterState; State hasQuarterState; State soldState; State winnerState; State state = soldOutState; int count = 0; String location; //构造器须要抛出RemoteException,由于超类是这样做的 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; if (numberGumballs > 0) state = noQuarterState; this.location = location; } public void insertQuarter() { state.insertQuarter(); } public void ejectQuarter() { state.ejectQuarter(); } public void turnCrank() { state.turnCrank(); state.dispense(); } void setState(State state) { this.state = state; } void releaseBall() { System.out.println("A gumball comes rolling out the slot..."); if (count != 0) { count = count - 1; } } public void refill(int count) { this.count = count; state = noQuarterState; } public int getCount() { return count; } public State getState() { return state; } public String getLocation() { return location; } //其它方法 } //在RMI register中注冊 public class GumballMachineTestDrive { public static void main(String[] args) { GumballMachineRemote gumballMachine = null; int count; if (args.length < 2) { System.out.println("GumballMachine <name> <inventory>"); System.exit(1); } try {//须要在实例化代码前加上try/catch。由于我们的构造器可能会抛出异常 count = Integer.parseInt(args[1]); gumballMachine = new GumballMachine(args[0], count); //我们也加入上对Naming.rebind的调用。用gumballmachine的名字公布GumballMachine的stub Naming.rebind("//" + args[0] + "/gumballmachine", gumballMachine); } catch (Exception e) { e.printStackTrace(); } } } //GumballMonitorclient public class GumballMonitor { //依赖此GumballMachineRemote远程接口,而不是详细的类 GumballMachineRemote machine; public GumballMonitor(GumballMachineRemote machine) { this.machine = machine; } public void report() { //当我们视图调用哪些终于都要通过网络发生的方法时,我么须要捕获全部可能发生的远程异常 try { System.out.println("Gumball Machine: " + machine.getLocation()); System.out.println("Current inventory: " + machine.getCount() + " gumballs"); System.out.println("Current state: " + machine.getState()); } catch (RemoteException e) { e.printStackTrace(); } } } //监视測试程序 public class GumballMonitorTestDrive { public static void main(String[] args) { String[] location = { "rmi://santafe.mightygumball.com/gumballmachine", "rmi://boulder.mightygumball.com/gumballmachine", "rmi://seattle.mightygumball.com/gumballmachine" }; GumballMonitor[] monitor = new GumballMonitor[location.length]; for (int i = 0; i < location.length; i++) { try { //为每一个远程机器创建一个代理,客户从Register中寻找代理,也就是stub对象 GumballMachineRemote machine = (GumballMachineRemote) Naming .lookup(location[i]); monitor[i] = new GumballMonitor(machine); System.out.println(monitor[i]); } catch (Exception e) { e.printStackTrace(); } } //遍历每台机器,打印报告 for (int i = 0; i < monitor.length; i++) { monitor[i].report(); } } }
虚拟代理
class ImageProxy implements Icon { ImageIcon imageIcon; URL imageURL; Thread retrievalThread; boolean retrieving = false; //我们将图像的url传入构造器中,这是我们希望显示的图像所在的位置 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) { //假设已经有了icon,就告诉它画出自己 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 { //此线程中我们实例化icon对象。其构造器会在图像载入完毕后才返回 imageIcon = new ImageIcon(imageURL, "CD Cover"); //当图像准备好后,我们告诉Swing须要重绘 c.repaint(); } catch (Exception e) { e.printStackTrace(); } } }); retrievalThread.start(); } } } } 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 { //建立框架和菜单 //创建一个图像代理,并指定初始URL Icon 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; } } }