代理模式-远程代理(学习笔记2021.09.10)
前言:
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
**意图:**为其他对象提供一种代理以控制对这个对象的访问。
**主要解决:**在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。
**何时使用:**想在访问一个类时做一些控制。
**如何解决:**增加中间层。
**关键代码:**实现与被代理类组合。
应用实例: 1、Windows 里面的快捷方式。 2、猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 3、买火车票不一定在火车站买,也可以去代售点。 4、spring aop。
优点: 1、职责清晰。 2、高扩展性。 3、智能化。
缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
**使用场景:**按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。
注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
前提条件
在之前的实现状态模式中, 糖果机公司的CEO又出了新需求,
他需要在本地的电脑上, 知道远程糖果机的状态、剩余糖果数量等等
远程代理说明:
一个简单的远程代理服务演示
下面使用远程代理模式实现远程监控糖果机
1.0 改造糖果机GumballMachine
使其可以接受远程服务调用
1- 为糖果机创建一个可远程调用的服务接口
2- 接口定义调用的方法, 并且所有传输的对象都是可正常序列化与反序列化
3- 糖果机
GumballMachine
实现该接口
// 1、2- 提供远程调用那些方法的服务接口, 继承rmi使其可以注册到rmi服务中心
public interface GumballMachineRemote extends Remote {
int getCount() throws RemoteException;
String getLocation() throws RemoteException;
// 该类型, 里面需要实现 public interface State extends Serializable
State getState() throws RemoteException;
}
State
类或者其所有实现类, 对应不想序列化进行传输发送的, 使用其关键字private transient GumballMachine gumballMachine;
/** 3- 糖果机 我们实现了GumballMachineRemote, 但是需要明确其当成服务使用, 并处理网络上的请求, 需要继承UnicastRemoteObject**/
public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote {
/**
* 每种状态对应需要操作的行为
*/
State soldOutState;
State noQuarterState;
State hasQuarterState;
State soldState;
/**
* 真实获取到然后执行的对应状态的操作行为
**/
State state;
int count = 0;
// 构造器需要抛出异常, 因为父类的构造器抛也是抛出的异常
public GumballMachine(int port,int numberGumballs) throws RemoteException{
// 初始化每一种状态对应需要操作的行为
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
this.count = numberGumballs;
// 当糖果数量大于0, 转换真实获取到然后执行的对应的没有投钱操作行为
if (numberGumballs > 0) {
state = noQuarterState;
} else {
// 当糖果数量小于0, 转换真实获取到然后执行的对应的没有货物操作行为
state = soldOutState;
}
}
2.0 注册到RMI
上
打开
CMD
命令, 输入:rmiregistry
调起JDK内置的RMI
服务,然后在运行rmi注册服务代码
@Test
public void myEST() throws Exception {
try {
synchronized (GumballMachineRemote.class) {
// 本地主机上的远程对象注册表Registry的实例,默认端口8090
LocateRegistry.createRegistry(8090);
// 创建一个远程对象
GumballMachineRemote gumballMachineRemote = new GumballMachine(2);
// 把远程对象注册到RMI注册服务器上,并命名为gumballMachineRemote
Naming.bind("rmi://localhost:8090/gumballMachineRemote", gumballMachineRemote);
System.out.println("======= 启动RMI服务成功! =======");
GumballMachineRemote.class.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
到此,我们的服务提供就完毕
3.0 进行消费服务, 打印糖果机状态
@Test
public void applicationTest() throws Exception {
GumballMachineRemote remote = (GumballMachineRemote) Naming.lookup("rmi://localhost:8090/gumballMachineRemote");
System.out.println(remote.getCount());
System.out.println(remote.getLocation());
}
// public void myEST() throws Exception {
2
深圳地区
1