《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;
		}
	}
}


原文地址:https://www.cnblogs.com/lxjshuju/p/7120919.html