概述
———————————————————————————————————————————————————
代理模式
—为另一对象提供替身或占位符以访问这个对象。
OO原则
———————————————————————————————————————————————————
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
- 类应该对扩展开放,对修改关闭
- 依赖抽象,不要以来具体类
- 只和朋友交谈
- 别找我,我会找你
- 类应该只有一个改变的理由
要点
———————————————————————————————————————————————————
- 代理模式为另一个对象提供代表,以便控制客户对对象访问,管理访问的方式有许多种。
- 远程代理管理客户和远程对象之间的交互。
- 虚拟代理控制访问实例化开销大的对象。
- 保护代理基于调用者控制对象方法的访问。
- 代理模式有许多变体,例如:缓存代理、同步代理、防火墙代理和写入时复制代理。
- 代理在结构上类似装饰者,但是目的不同。
- 装饰者模式为对象加上行为,而代理是控制访问。
- Java内置的代理支持,可以根据需要建立动态代理,并将所有调用分配到所选的处理器。
- 就和其他的包装者(wrapper)一样,代理会造成你的设计中类的数目增加。
例子:实现可以远程控制的糖果机
———————————————————————————————————————————————————
代码的改变可以对照“状态模式”那一篇博客
代理模式并不是那么容易理解,需要好好介绍一下
远程代理的角色
远程代理就好比“远程对象的本地代表”。何谓“远程对象”?这是一种对象,活在不同的Java虚拟机堆中(更一般的说法为,在不同的地址空间运行的远程对象)。何谓“本地代表”?这是一种可以由本地方法调用的对象,其行为会转发到远程对象中。
简单来说,代理就是一个本地对象,是客户直接打交道的对象,然而这个本地对象再跟真正的远程对象进行沟通,远程对象把请求的结果返回给代理,再由代理把结果返回给客户。这是远程控制的整个流程。
在本例子当中,糖果机充当的角色是真正的远程对象,是代理服务的对象。而代理呢,是要通过监视器从远程服务器中注册返回得到的。这里涉及到Java的RMI(远程方法调用),不是设计模式的内容,不多说。
我们要知道的就是,代理对象是通过RMI Registry得到的,它叫做stub(桩),stub扮演的是客户辅助对象,实在客户堆里的;然而在Java RMI中在服务器堆中skeleton(骨架)作为服务辅助对象。
不知道大家能不能看明白,其实在《Head First设计模式》当中,讲解得非常详细了,图文并茂,看几遍应该就能理解远程代理的操作流程是怎样的了。
来看看糖果机的远程代理实现吧
客户端里有:
GumballMonitor:这是我们的监视器代码,它使用代理来和远程糖果机沟通。
GumballStub:这是我们的代理
服务器端有:
GumballSkeleton:这是我们的服务器辅助对象
GumballMachine:这是我们的服务对象,它为客户暴露一个远程接口以供使用。
让GumballMachine准备好当一个远程服务
GumabllMachineRemote接口
- package gumballrmi;
-
- import java.rmi.Remote;
- import java.rmi.RemoteException;
-
-
-
-
-
- public interface GumballMachineRemote extends Remote {
- public int getCount() throws RemoteException;
- public String getLocation() throws RemoteException;
- public State getState() throws RemoteException;
- }
修改状态接口
- package gumballrmi;
-
- import java.io.*;
-
-
-
-
- public interface State extends Serializable {
-
- public void insertQuarter();
- public void ejectQuarter();
- public void turnCrank();
- public void dispense();
- }
修改状态实现类
- package gumballrmi;
-
- public class NoQuarterState implements State {
-
- transient GumballMachine gumballMachine;
-
- public NoQuarterState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("You inserted a quarter");
- gumballMachine.setState(gumballMachine.getHasQuarterState());
- }
-
- public void ejectQuarter() {
- System.out.println("You haven't inserted a quarter");
- }
-
- public void turnCrank() {
- System.out.println("You turned, but there's no quarter");
- }
-
- public void dispense() {
- System.out.println("You need to pay first");
- }
-
- public String toString() {
- return "waiting for quarter";
- }
- }
HasQuarterState.java
- package gumballrmi;
-
- import java.util.Random;
-
- public class HasQuarterState implements State {
- Random randomWinner = new Random(System.currentTimeMillis());
- transient GumballMachine gumballMachine;
-
- public HasQuarterState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("You can't insert another quarter");
- }
-
- public void ejectQuarter() {
- System.out.println("Quarter returned");
- gumballMachine.setState(gumballMachine.getNoQuarterState());
- }
-
- public void turnCrank() {
- System.out.println("You turned...");
- int winner = randomWinner.nextInt(10);
- if((winner == 0) && (gumballMachine.getCount() > 1)) {
- gumballMachine.setState(gumballMachine.getWinnerState());
- } else {
- gumballMachine.setState(gumballMachine.getSoldState());
- }
- }
-
- public void dispense() {
- System.out.println("No gumball dispensed");
- }
-
- public String toString() {
- return "waiting for turn of crank";
- }
- }
SoldOutState.java
- package gumballrmi;
-
- public class SoldOutState implements State {
- transient GumballMachine gumballMachine;
-
- public SoldOutState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("You can't insert a quarter, the machine is sold out");
- }
-
- public void ejectQuarter() {
- System.out.println("You can't eject, you haven't inserted a quarter yet");
- }
-
- public void turnCrank() {
- System.out.println("You turned, but there are no gumballs");
- }
-
- public void dispense() {
- System.out.println("No gumball dispensed");
- }
-
- public String toString() {
- return "sold out";
- }
- }
SoldState.java
- package gumballrmi;
-
- public class SoldState implements State {
-
- transient GumballMachine gumballMachine;
-
- public SoldState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("Please wait, we're already giving you a gumball");
- }
-
- public void ejectQuarter() {
- System.out.println("Sorry, you already turned the crank");
- }
-
- public void turnCrank() {
- System.out.println("Turning twice doesn't get you another gumball!");
- }
-
- public void dispense() {
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() > 0) {
- gumballMachine.setState(gumballMachine.getNoQuarterState());
- } else {
- System.out.println("Oops, out of gumballs!");
- gumballMachine.setState(gumballMachine.getSoldOutState());
- }
- }
-
- public String toString() {
- return "dispensing a gumball";
- }
- }
WinnerState.java
- package gumballrmi;
-
- public class WinnerState implements State {
- transient GumballMachine gumballMachine;
-
- public WinnerState(GumballMachine gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void insertQuarter() {
- System.out.println("Please wait, we're already giving you a Gumball");
- }
-
- public void ejectQuarter() {
- System.out.println("Please wait, we're already giving you a Gumball");
- }
-
- public void turnCrank() {
- System.out.println("Turning again doesn't get you another gumball!");
- }
-
- public void dispense() {
- System.out.println("YOU'RE A WINNER! You get two gumballs for your quarter");
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() == 0) {
- gumballMachine.setState(gumballMachine.getSoldOutState());
- } else {
- gumballMachine.releaseBall();
- if (gumballMachine.getCount() > 0) {
- gumballMachine.setState(gumballMachine.getNoQuarterState());
- } else {
- System.out.println("Oops, out of gumballs!");
- gumballMachine.setState(gumballMachine.getSoldOutState());
- }
- }
- }
-
- public String toString() {
- return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";
- }
- }
监视器
- package gumballrmi;
-
- import java.rmi.RemoteException;
-
-
-
-
-
-
-
-
- public class GumballMonitor {
- GumballMachineRemote gumballMachine;
-
- public GumballMonitor(GumballMachineRemote gumballMachine) {
- this.gumballMachine = gumballMachine;
- }
-
- public void report() {
- try {
- System.out.println("Gumball Machine: " + gumballMachine.getLocation());
- System.out.println("Current inventory: " + gumballMachine.getCount() + " gumballs");
- System.out.println("Current State: " + gumballMachine.getState());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
- }
糖果机
- package gumballrmi;
-
- import java.rmi.Naming;
-
- public class GumballMachineTestDrive {
-
- public static void main(String[] args) {
- GumballMachineRemote gumballMachine = null;
- int count = 0;
-
- if(args.length < 2) {
- System.out.println("GumballMachine<name> <inventory>");
- System.exit(1);
- }
- try {
- count = Integer.parseInt(args[1]);
- gumballMachine = new GumballMachine(args[0], count);
- Naming.rebind("//" + args[0] + "/gumballmachine", gumballMachine);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
以上也就是制作远程服务的步骤
步骤一:制作远程接口
步骤二:制作远程的实现
步骤三:利用rmic产生的stub和skeleton
步骤四:启动RMI registry
步骤五:开始远程服务
在代理模式中还有虚拟代理和保护代理,在这里就只讨论远程代理,是用得比较多的一种,其他的可以参考《Head First 设计模式》。