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

	//返回值将从服务器经过网络运回客户,所以必须是原语类型或可序列化类型
	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实例变量前面加上transient关键字,这样就可以高考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();
		}
	}
}

//GumballMonitor客户端
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;
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值