9 Proxy 设计模式

9.1简介

在本课中,我们将讨论一个结构模式,代理模式。 代理模式为另一个对象提供代理或占位符来控制对其的访问。

代理模式具有许多不同的变体。 一些重要的变体是远程代理,虚拟代理和保护代理。 在本课中,我们将更多地了解这些变体,我们将用Java实现它们中的每一个。 但在我们这样做之前,让我们了解更多关于代理模式的内容。

9.2什么是代理模式

代理模式用于创建一个代表性的对象,用于控制对另一个对象的访问,这对于创建或需要保护而言可能是远程的,昂贵的。

控制访问对象的一个原因是延迟其创建和初始化的全部成本,直到我们实际需要使用它为止。 另一个原因可能是作为一个居住在不同JVM中的对象的当地代表。 代理在控制对原始对象的访问方面非常有用,特别是当对象应具有不同的访问权限时。

在代理模式中,客户端不直接与原始对象通话,而是将其委托给调用原始对象方法的代理对象。 重要的一点是,客户端不知道代理服务器,代理服务器作为客户端的原始对象。 但是这种方法有很多变化,我们很快就会看到。

让我们看看代理模式及其重要参与者的结构。


•Proxy:

1a。 保留一个引用,让代理访问真正的主题。 如果RealSubject和Subject接口相同,Proxy可能会引用一个Subject。

1b。 提供与主题相同的界面,以便代理可以替代真实主题。

1c。 控制对真实主题的访问,并可能负责创建和删除它。

•Subject:

2a。 定义RealSubject和Proxy的通用接口,以便可以在RealSubject所期望的任何位置使用代理。

•RealSubject:

3a。 定义代理所代表的真实对象。

 代理模式有三种主要的变体:

•远程代理为不同地址空间中的对象提供本地代理。

•虚拟代理按需创建昂贵的对象。

•保护代理控制对原始对象的访问。 当对象应具有不同的访问权限时,保护代理非常有用。

我们将在下一节中逐一讨论这些代理。

9.3远程代理

有一家比萨公司,在不同地点设有分店。公司的所有者从公司的工作人员那里得到各个销售点的每日报告。 Pizza公司支持的当前应用程序是桌面应用程序,而不是Web应用程序。因此,店主必须要求员工生成报告并将其发送给他。但是现在,主人想要自己生成并检查报告,以便在任何人无需任何帮助的情况下,只要他想要就能生成报告。店主希望你为他开发一个应用程序。

这里的问题是所有的应用程序都运行在它们各自的JVM上,Report Checker应用程序(我们将尽快设计)应该在所有者的本地系统中运行。生成报告所需的对象不在所有者的系统JVM中,并且不能直接调用远程对象。

远程代理被用来解决这个问题。我们知道报告是由用户生成的,因此有一个对象需要生成报告。我们所需要的只是联系驻留在远程位置的对象,以获得我们想要的结果。远程代理服务器充当远程对象的本地代表。远程对象是位于不同JVM的堆中的对象。您可以将方法调用到将该调用转发给远程对象的本地对象。

您的客户端对象就像进行远程方法调用一样。但它调用堆本地代理对象上的方法来处理网络通信的所有低级细节。

Java支持使用RMI驻留在两个不同位置(或两个不同的JVM)的两个对象之间的通信。 RMI是远程方法调用,用于构建客户端和服务帮助对象,直至使用与远程服务相同的方法创建客户端帮助对象。使用RMI,您不必自己编写任何网络或I / O代码。通过您的客户端,您可以调用远程方法,就像在客户端本地JVM中运行的对象的常规方法调用一样。

RMI还提供运行基础结构以使其全部工作,其中包括客户端可用于查找和访问远程对象的查找服务。 RMI调用和本地方法调用之间有一个区别。客户端帮助程序通过网络发送方法调用,因此存在涉及RMI调用的网络和I / O。

现在我们来看看代码。我们有一个接口ReportGenerator及其具体实现ReportGener atorImpl已经在不同位置的JVM上运行。首先要创建一个远程服务,我们需要更改代码。

ReportGenerator接口现在看起来像这样:

package com.javacodegeeks.patterns.proxypattern.remoteproxy;import java.rmi.Remote;

import java.rmi.RemoteException;

public interface ReportGenerator extends Remote{

public String generateDailyReport() throws RemoteException;

}

这是一个定义客户端可以远程调用的方法的远程接口。 这是客户将用作服务的类类型。 存根和实际服务都将执行此操作。 接口中的方法返回一个String对象。 您可以返回方法中的任何对象; 这个对象将通过从服务器到客户端的线路发送,所以它必须是可序列化的。 请注意,此接口中的所有方法都应抛出RemoteException。

package com.javacodegeeks.patterns.proxypattern.remoteproxy;

import java.rmi.Naming;import java.rmi.RemoteException;import java.rmi.server.UnicastRemoteObject;import java.util.Date;

public class ReportGeneratorImpl extends UnicastRemoteObject implements ReportGenerator{        

private static final long serialVersionUID = 3107413009881629428L;

protected ReportGeneratorImpl() throws RemoteException {

}

@Overridepublic String generateDailyReport() throws RemoteException {

        StringBuilder sb = new StringBuilder();

sb.append("********************Location X Daily Report********************");

sb.append("\\n Location ID: 012");
sb.append("\\n Today’s Date: "+new Date());
sb.append("\\n Total Pizza’s Sell: 112");
sb.append("\\n Total Price: $2534");
sb.append("\\n Net Profit: $1985");
sb.append("\\n***************************************************************");        

return sb.toString();

}public static void main(String[] args) {

try {

ReportGenerator reportGenerator = new ReportGeneratorImpl();

Naming.rebind("PizzaCoRemoteGenerator", reportGenerator);

} catch (Exception e) {

e.printStackTrace();

}

}

}

上面的类是真正的工作的远程实现。这是客户想要调用方法的对象。该类扩展了UnicastRemoteObject,为了作为远程服务对象工作,您的对象需要一些与远程相关的功能。最简单的方法是从java.rmi.server包中扩展UnicastRemoteObject,并让该类为您完成工作。

UnicastRemoteObject类构造函数抛出一个RemoteException,因此您需要编写一个声明RemoteException的无参数构造函数。

要使远程服务可用于客户端,您需要向RMI注册表注册该服务。您可以通过实例化并将其放入RMI注册表中来实现此目的。当您注册实现对象时,RMI系统实际上将存根放入注册表中,因为这是客户端需要的。 Naming.rebind方法用于注册对象。它有两个参数,第一个是用于命名服务的字符串,而另一个参数是由客户端获取以使用该服务的对象。

现在,要创建存根,需要在远程实现类上运行rmic。 rmic工具随Java软件开发小孩一起提供,需要一个服务实现并创建一个新的存根。您应打开命令提示符(cmd)并从远程实施所在的目录运行rmic。

下一步是运行rmiregistry,启动一个终端并启动注册表,只需键入命令rmiregistry。但一定要从可以访问你的类的目录中启动它。

最后一步是启动服务,即运行您的远程类的具体实现,在这种情况下,类是ReportG eneratorImpl。

到目前为止,我们已经创建并运行了一项服务。现在,让我们看看客户端将如何使用它。披萨公司所有者的报告申请将使用该服务来生成和检查报告。我们需要将接口ReportGenerator和存根提供给将使用该服务的客户端。您可以简单地交付该服务中所需的存根和任何其他类或接口。

package com.javacodegeeks.patterns.proxypattern.remoteproxy;import java.rmi.Naming;public class ReportGeneratorClient {

public static void main(String[] args) {        

new ReportGeneratorClient().generateReport();

}

public void generateReport(){

try {

ReportGenerator reportGenerator = (ReportGenerator)Naming.lookup("rmi://127.0.0.1/PizzaCoRemoteGenerator");

System.out.println(reportGenerator.generateDailyReport());

} catch (Exception e) {

}

e.printStackTrace();

}

}

上面的程序将有如下结果:


上面的类进行命名查找并检索用于生成每日报告的对象。 您需要提供主机名的IP和用于绑定服务的名称。 它的其余部分看起来像一个普通的旧方法调用。

总而言之,远程代理服务器充当位于不同JVM中的对象的本地代理。 对代理的方法调用导致呼叫通过有线传输,远程调用,结果返回给代理,然后返回给客户端。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • 目录 本文的结构如下: 引言 什么是代理模式 模式的结构 典型代码 代理模式分类 代码示例 代理模式和装饰者模式的...
    w1992wishes阅读 1,517评论 0 13
  • 代理模式——远程代理(Java RMI) @(设计模式) 一、远程代理——大使 在日常开发中,我们经常会有本地服务...
    理查德成阅读 5,512评论 0 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,591评论 18 139
  • Java 面试题 整理自牛客网 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟...
    GuaKin_Huang阅读 10,657评论 19 265
  • 总评:感觉是官方文档的衍生阅读,重点不在于介绍TypeScript语法本身,语法就是第一章的部分,不到30页的说明...
    沉寂之舟阅读 1,461评论 0 0