zoukankan      html  css  js  c++  java
  • 《Head First 设计模式》学习笔记——代理模式

    设计模式
    代理模式:为还有一个对象提供一个替身或占位符以控制对这个对象的訪问。
    使用代理模式创建代表对象,让代表对象控制某对象的訪问,被代理的对象能够使远程的对象(远程代理)、创建开销大的对象(虚拟代理),或须要安全控制的对象(保护代理)。

    远程代理:能够作为还有一个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;
    		}
    	}
    }
    


  • 相关阅读:
    CentOS7安装MySql5.7
    环境变量配置
    Spring 注解
    MySQL
    常用命令
    Android Studio & IntelliJ IDEA常见问题与设置
    order by、group by、having的区别
    把WebStrom添加到右键菜单
    解决github访问速度慢的问题
    docker修改时区
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7120919.html
Copyright © 2011-2022 走看看