设计模式学习--代理模式(Proxy Pattern)

设计模式学习--代理模式(Proxy Pattern)

概述

———————————————————————————————————————————————————
代理模式—为另一对象提供替身或占位符以访问这个对象。


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;

/**
 * 让GumballMachine准备好当一个远程服务
 * @author wwj
 * 代理模式的使用例子
 */
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.*;

/**
 * 2013/7/13
 * @author wwj
 * 扩展Serializable接口,则State的所有子类就可以在网络上传送了
 */
public interface State extends Serializable {
 
	public void insertQuarter();
	public void ejectQuarter();
	public void turnCrank();
	public void dispense();
}

修改状态实现类
package gumballrmi;

public class NoQuarterState implements State {
	//对于State的每个实现,我们都在GumballMachine实例变量前面加上transient关键字,这就就告诉JVM不要序列化这个字段
    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);	//参数0~10的随机数
		if((winner == 0) && (gumballMachine.getCount() > 1)) {	//如果随机树为0,且足够的糖果的话,则可以得到两颗糖果
			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;

/**
 * 
 * @author wwj
 * 糖果监视器,以便取得机器的位置、糖果的库存量以及当前机器的状态
 * 并打印一份可爱的报告
 * 这是我们的监视器代码,它使用代理和远程糖果机沟通
 */
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.RemoteException;
import java.rmi.server.UnicastRemoteObject;

/**
 * 2013/7/13
 * @author wwj
 * 糖果机成为一个远程服务
 * 代理模式:
 */
public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote{
	
	State soldOutState;			//售空状态
	State noQuarterState;		//没有投入25分钱
	State hasQuarterState;		//有25分钱了
	State soldState;			//出售状态
	State winnerState;			//10%的中奖率
	
	State state = soldOutState;
	int count = 0;
	String location;			//新增,位置字段		
	
	
	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 String getLocation() {
		return 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;
	}
	
	public State getState() {
		return state;
	}


	void releaseBall() {
		System.out.println("A gumball comes rolling out the slot...");
		if(count != 0) {
			count = count - 1;
		}
	}


	public State getSoldOutState() {
		return soldOutState;
	}


	public State getNoQuarterState() {
		return noQuarterState;
	}


	public State getHasQuarterState() {
		return hasQuarterState;
	}


	public State getSoldState() {
		return soldState;
	}
	
	
	public State getWinnerState() {
		return winnerState;
	}


	public int getCount() {
		return count;
	}


	public String toString() {
		StringBuffer result = new StringBuffer();
		result.append("\nMighty Gumball, Inc.");
		result.append("\nJava-enabled Standing Gumball Model #2004");
		result.append("\nInventory: " + count + " gumball");
		if (count != 1) {
			result.append("s");
		}
		result.append("\n");
		result.append("Machine is " + state + "\n");
		return result.toString();
	}
	
}

在RMI registry中注册。。。。。


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 设计模式》。











  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java设计模式是一组经过实践验证的面向对象设计原则和模式,可以帮助开发人员解决常见的软件设计问题。下面是常见的23种设计模式: 1. 创建型模式(Creational Patterns): - 工厂方法模式(Factory Method Pattern) - 抽象工厂模式(Abstract Factory Pattern) - 单例模式(Singleton Pattern) - 原型模式(Prototype Pattern) - 建造者模式(Builder Pattern) 2. 结构型模式(Structural Patterns): - 适配器模式(Adapter Pattern) - 桥接模式(Bridge Pattern) - 组合模式(Composite Pattern) - 装饰器模式(Decorator Pattern) - 外观模式(Facade Pattern) - 享元模式(Flyweight Pattern) - 代理模式Proxy Pattern) 3. 行为型模式(Behavioral Patterns): - 责任链模式(Chain of Responsibility Pattern) - 命令模式(Command Pattern) - 解释器模式(Interpreter Pattern) - 迭代器模式(Iterator Pattern) - 中介者模式(Mediator Pattern) - 备忘录模式(Memento Pattern) - 观察者模式(Observer Pattern) - 状态模式(State Pattern) - 策略模式(Strategy Pattern) - 模板方法模式(Template Method Pattern) - 访问者模式(Visitor Pattern) 4. 并发型模式(Concurrency Patterns): - 保护性暂停模式(Guarded Suspension Pattern) - 生产者-消费者模式(Producer-Consumer Pattern) - 读写锁模式(Read-Write Lock Pattern) - 信号量模式(Semaphore Pattern) - 线程池模式(Thread Pool Pattern) 这些设计模式可以根据问题的特点和需求来选择使用,它们提供了一些可复用的解决方案,有助于开发高质量、可维护且易于扩展的软件系统。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小巫技术博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值