【软件设计】常用设计模式--代理模式

文章目录

  • 代理模式(Proxy Pattern)
    • 1. 概念
    • 2. 模式结构
    • 3. UML 类图
    • 4.实现方式
      • C# 示例
        • 步骤1:定义主题接口
        • 步骤2:实现真实主题
        • 步骤3:实现代理类
        • 步骤4:客户端使用代理模式
        • 输出结果:
      • Java 示例
        • 步骤1:定义主题接口
        • 步骤2:实现真实主题
        • 步骤3:实现代理类
        • 步骤4:客户端使用代理模式
        • 输出结果:
    • 5. 代理模式的类型
      • 5.1 虚拟代理
      • 5.2 远程代理
        • 实现步骤
          • 步骤1:定义主题接口
          • 步骤2:实现真实主题
          • 步骤3:实现远程代理
          • 步骤4:客户端使用远程代理
      • 5.3 保护代理
      • 5.4 智能代理
        • 实现步骤
          • 步骤1:定义主题接口
          • 步骤2:实现真实主题
          • 步骤3:实现智能代理
          • 步骤4:客户端使用智能代理
      • 5.5 应用场景
    • 6. 优点
    • 7. 缺点
    • 8. 代理模式应用场景
    • 9.代理模式变体
      • 9.1 虚拟代理(Virtual Proxy)
        • 实现步骤
          • 步骤1:定义主题接口
          • 步骤2:实现真实主题
          • 步骤3:实现虚拟代理
          • 步骤4:客户端使用虚拟代理
        • 应用场景
      • 9.2 保护代理(Protection Proxy)
        • 实现步骤
          • 步骤1:定义主题接口
          • 步骤2:实现真实主题
          • 步骤3:实现保护代理
          • 步骤4:客户端使用保护代理
        • 应用场景
      • 9.3 缓存代理(Caching Proxy)
        • 实现步骤
          • 步骤1:定义主题接口
          • 步骤2:实现真实主题
          • 步骤3:实现缓存代理
          • 步骤4:客户端使用缓存代理
        • 应用场景
    • 10.总结

代理模式(Proxy Pattern)

1. 概念

代理模式是一种结构型设计模式,它为另一个对象提供了一个替身或占位符,以控制对该对象的访问。代理可以代替原对象执行操作、控制访问权限、延迟加载等。这种模式的关键在于代理对象和被代理对象实现相同的接口,以确保它们可以互换。

2. 模式结构

代理模式的核心角色包括:

  • 主题(Subject):定义了代理对象和真实对象的公共接口。
  • 真实主题(RealSubject):实际的业务逻辑类,代理对象通过控制对它的访问来扩展功能。
  • 代理(Proxy):持有对 RealSubject 的引用,并可以在调用前后对其操作进行控制或扩展。

3. UML 类图

Subject
+Request()
Proxy
+ RealSubject: Subject
+Request()
RealSubject
+Request()

4.实现方式

C# 示例

步骤1:定义主题接口
public interface ISubject
{void Request();
}
步骤2:实现真实主题
public class RealSubject : ISubject
{public void Request(){Console.WriteLine("RealSubject: Handling Request.");}
}
步骤3:实现代理类
public class Proxy : ISubject
{private RealSubject _realSubject;public void Request(){if (_realSubject == null){_realSubject = new RealSubject();}Console.WriteLine("Proxy: Controlling access before forwarding the request.");_realSubject.Request();}
}
步骤4:客户端使用代理模式
class Program
{static void Main(string[] args){ISubject proxy = new Proxy();proxy.Request();}
}
输出结果:
Proxy: Controlling access before forwarding the request.
RealSubject: Handling Request.

Java 示例

步骤1:定义主题接口
public interface Subject {void request();
}
步骤2:实现真实主题
public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现代理类
public class Proxy implements Subject {private RealSubject realSubject;@Overridepublic void request() {if (realSubject == null) {realSubject = new RealSubject();}System.out.println("Proxy: Controlling access before forwarding the request.");realSubject.request();}
}
步骤4:客户端使用代理模式
public class Main {public static void main(String[] args) {Subject proxy = new Proxy();proxy.request();}
}
输出结果:
Proxy: Controlling access before forwarding the request.
RealSubject: Handling request.

5. 代理模式的类型

5.1 虚拟代理

虚拟代理用于控制资源密集型对象的实例化,常用于延迟加载(Lazy Initialization)场景。代理类在实际使用时才实例化真实对象,从而节省系统资源。

  • 示例:当一个图像很大且加载时间较长时,使用虚拟代理可以延迟图像的加载,只有当图像真正需要显示时才进行加载。
public class ImageProxy : IImage
{private RealImage _realImage;private string _fileName;public ImageProxy(string fileName){_fileName = fileName;}public void Display(){if (_realImage == null){_realImage = new RealImage(_fileName);}_realImage.Display();}
}

5.2 远程代理

远程代理为位于不同地址空间的对象(如通过网络通信的对象)提供代理。客户端通过代理访问远程服务器上的对象,而不直接处理复杂的通信逻辑。

  • 示例:当客户端需要访问远程的Web服务或数据库时,使用远程代理可以将网络通信的复杂性隐藏在代理类中。
实现步骤
步骤1:定义主题接口

与真实对象和代理对象共享相同的接口,以便客户端可以通过代理访问。

public interface Subject {void request();
}
步骤2:实现真实主题

真实对象实现了主题接口,并包含了实际的业务逻辑。

public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现远程代理

远程代理通常会处理网络通信的细节,比如使用HTTP、Socket等。它会将请求发送到远程服务器,接收响应并返回给客户端。

import java.io.*;
import java.net.*;public class RemoteProxy implements Subject {private String serverAddress;public RemoteProxy(String serverAddress) {this.serverAddress = serverAddress;}@Overridepublic void request() {try {Socket socket = new Socket(serverAddress, 8080);PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out.println("Request from Remote Proxy");String response = in.readLine();System.out.println("Response from Real Subject: " + response);in.close();out.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
步骤4:客户端使用远程代理

客户端通过远程代理调用真实主题的功能。

public class Client {public static void main(String[] args) {Subject proxy = new RemoteProxy("localhost");proxy.request();}
}

服务器端示例
服务器端接收请求并返回响应:

import java.io.*;
import java.net.*;public class Server {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(8080);System.out.println("Server is running...");while (true) {Socket clientSocket = serverSocket.accept();PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));String request = in.readLine();System.out.println("Received: " + request);out.println("Handled by Real Subject");in.close();out.close();clientSocket.close();}}
}

5.3 保护代理

保护代理用于控制对原始对象的访问,主要是限制某些客户端的权限。代理会根据访问者的权限决定是否可以访问真实对象。

  • 示例:在访问控制系统中,代理可以根据用户的角色决定是否授予对特定资源的访问权。
public class ProtectedProxy : ISubject
{private RealSubject _realSubject;private string _userRole;public ProtectedProxy(string userRole){_userRole = userRole;}public void Request(){if (_userRole == "Admin"){_realSubject = new RealSubject();_realSubject.Request();}else{Console.WriteLine("Access Denied: You don't have permission to perform this operation.");}}
}

5.4 智能代理

智能代理可以在真实对象操作的前后执行一些附加操作,例如记录日志、统计调用次数、缓存结果等。

  • 示例:在Web应用程序中,智能代理可以用于记录每个请求的处理时间。
public class LoggingProxy : ISubject
{private RealSubject _realSubject;public void Request(){Console.WriteLine("Logging: Before executing the request.");if (_realSubject == null){_realSubject = new RealSubject();}_realSubject.Request();Console.WriteLine("Logging: After executing the request.");}
}
实现步骤
步骤1:定义主题接口

与之前相同,定义一个公共接口。


public interface Subject {void request();
}
步骤2:实现真实主题

实现主题接口的真实对象。

public class RealSubject implements Subject {@Overridepublic void request() {System.out.println("RealSubject: Handling request.");}
}
步骤3:实现智能代理

智能代理在调用真实对象的请求方法前后执行一些附加操作,比如记录日志或计算执行时间。

public class SmartProxy implements Subject {private RealSubject realSubject;public SmartProxy() {this.realSubject = new RealSubject();}@Overridepublic void request() {System.out.println("SmartProxy: Logging before request.");long startTime = System.currentTimeMillis();realSubject.request();long endTime = System.currentTimeMillis();System.out.println("SmartProxy: Logging after request. Execution time: " + (endTime - startTime) + " ms");}
}
步骤4:客户端使用智能代理

客户端通过智能代理调用真实主题。

public class Client {public static void main(String[] args) {Subject proxy = new SmartProxy();proxy.request();}
}

5.5 应用场景

远程代理
场景:在分布式系统中,客户端需要访问远程服务,远程代理负责处理网络通信和请求转发。
应用:RPC(远程过程调用)、RESTful API等场景。
智能代理
场景:需要对方法调用进行监控、统计或其他增强功能,智能代理可以提供附加的处理逻辑。
应用:日志记录、性能监控、缓存管理等场景。

6. 优点

  • 控制对象访问:代理模式可以控制对真实对象的访问,添加权限控制、延迟加载、网络通信等功能。
  • 节省系统资源:虚拟代理可以在对象真正需要时才创建,从而节省资源。
  • 增强功能:代理可以在真实对象执行操作前后添加额外的功能,如日志记录、缓存等。

7. 缺点

  • 增加复杂性:由于引入了代理类,系统变得更加复杂,增加了类的数量。
  • 性能开销:代理可能导致额外的开销,特别是在处理远程调用或过度使用智能代理时。

8. 代理模式应用场景

  • 远程代理:当需要访问远程对象时,可以使用远程代理隐藏通信的细节。
  • 虚拟代理:当需要延迟加载资源密集型对象时,可以使用虚拟代理。
  • 访问控制:当需要控制对某些资源或对象的访问权限时,保护代理是一个理想的选择。
  • 性能优化:使用智能代理可以在不改变原有业务逻辑的情况下,优化性能或增加功能。

9.代理模式变体

9.1 虚拟代理(Virtual Proxy)

虚拟代理用于延迟加载资源密集型对象的实例化,直到需要时才创建真实对象。这样可以节省系统资源,避免不必要的开销。

实现步骤
步骤1:定义主题接口
public interface Image {void display();
}
步骤2:实现真实主题
public class RealImage implements Image {private String fileName;public RealImage(String fileName) {this.fileName = fileName;loadImageFromDisk();}private void loadImageFromDisk() {System.out.println("Loading " + fileName);}@Overridepublic void display() {System.out.println("Displaying " + fileName);}
}
步骤3:实现虚拟代理
public class ImageProxy implements Image {private RealImage realImage;private String fileName;public ImageProxy(String fileName) {this.fileName = fileName;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(fileName);}realImage.display();}
}
步骤4:客户端使用虚拟代理
public class Client {public static void main(String[] args) {Image image = new ImageProxy("test_image.jpg");image.display(); // 只在此处加载image.display(); // 直接显示,不再加载}
}
应用场景
  • 适用于需要加载大型对象的场景,例如图像、视频等。
  • 在图形界面应用中,通常使用虚拟代理来延迟加载图形组件。

9.2 保护代理(Protection Proxy)

保护代理控制对真实对象的访问,主要用于权限管理。它根据客户端的身份或角色决定是否允许访问真实对象。

实现步骤
步骤1:定义主题接口
public interface Document {void view();
}
步骤2:实现真实主题
public class RealDocument implements Document {@Overridepublic void view() {System.out.println("Viewing Document");}
}
步骤3:实现保护代理
public class ProtectionProxy implements Document {private RealDocument realDocument;private String userRole;public ProtectionProxy(String userRole) {this.userRole = userRole;}@Overridepublic void view() {if (userRole.equals("Admin")) {if (realDocument == null) {realDocument = new RealDocument();}realDocument.view();} else {System.out.println("Access Denied: You do not have permission to view this document.");}}
}
步骤4:客户端使用保护代理
public class Client {public static void main(String[] args) {Document doc = new ProtectionProxy("User");doc.view(); // Access DeniedDocument adminDoc = new ProtectionProxy("Admin");adminDoc.view(); // Access Granted}
}
应用场景
  • 适用于敏感数据或操作,需要根据用户权限控制访问的场景。
  • 在企业级应用中常见,用于控制对重要文档或资源的访问。

9.3 缓存代理(Caching Proxy)

缓存代理在调用真实对象的方法前检查是否已经缓存了结果。如果有,则直接返回缓存结果,否则调用真实对象并将结果存入缓存。

实现步骤
步骤1:定义主题接口
public interface Data {String fetchData();
}
步骤2:实现真实主题
public class RealData implements Data {@Overridepublic String fetchData() {return "Data from Real Data Source";}
}
步骤3:实现缓存代理
import java.util.HashMap;public class CachingProxy implements Data {private RealData realData;private HashMap<String, String> cache;public CachingProxy() {this.realData = new RealData();this.cache = new HashMap<>();}@Overridepublic String fetchData() {if (cache.containsKey("data")) {System.out.println("Returning cached data.");return cache.get("data");}String data = realData.fetchData();cache.put("data", data);return data;}
}
步骤4:客户端使用缓存代理
public class Client {public static void main(String[] args) {Data dataProxy = new CachingProxy();System.out.println(dataProxy.fetchData()); // First call fetches dataSystem.out.println(dataProxy.fetchData()); // Subsequent call returns cached data}
}
应用场景
  • 适用于数据查询频繁但变化不大的场景,例如Web应用中的数据库查询结果。
  • 可以显著提高性能,减少对真实数据源的调用次数。

10.总结

代理模式在控制对象访问和增强系统功能方面提供了很大的灵活性,且每种变体都有其独特的用处,需要根据需求进行选择和实施。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/57699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EXCELL中如何两条线画入一张图中,标记坐标轴标题?

1&#xff0c;打开excel&#xff0c;左击选中两列&#xff0c; 2&#xff0c;菜单栏>“插入”>”二维折线图”选中一个 3&#xff0c;选中出现的两条线中的一条右击>最下一行&#xff0c;“设置数据系列格式” 4&#xff0c;右测“系列选项中”>点击“次坐标轴” 5…

龙蟠科技业绩压力显著:资产负债率持续攀升,产能利用率也不乐观

《港湾商业观察》施子夫 黄懿 去年十月至今两度递表后&#xff0c;10月17日&#xff0c;江苏龙蟠科技股份有限公司(以下简称&#xff0c;龙蟠科技&#xff1b;603906.SH&#xff0c;02465.HK)通过港交所主板上市聆讯。 很快&#xff0c;龙蟠科技发布公告称&#xff0c;公司全…

低代码开发详解与行业应用指南

低代码开发简化软件开发&#xff0c;助力企业数字化转型。ZohoCreator应用于零售、制造、教育、IT、医疗、房地产等行业&#xff0c;提升效率、降低成本。灵活定价&#xff0c;支持免费试用&#xff0c;助力企业快速实现数字化。 一、低代码开发是什么&#xff1f; 低代码开发…

青少年编程能力等级测评CPA C++五级试卷(1)

青少年编程能力等级测评CPA C五级试卷&#xff08;1&#xff09; 一、单项选择题&#xff08;共15题&#xff0c;每题3分&#xff0c;共45分&#xff09; CP5_1_1.下列有关类的重用意义的叙述中&#xff0c;不正确的是&#xff08; &#xff09;。 A&#x…

栈(数据结构)——C语言

1 概念与结构 栈&#xff1a;⼀种特殊的线性表&#xff0c;其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作 的⼀端称为栈顶&#xff0c;另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 压栈&#…

如何动态改变本地的ip

在当今数字化时代&#xff0c;网络连接已成为我们日常生活和工作中不可或缺的一部分。无论是出于隐私保护、突破地域限制&#xff0c;还是为了测试和优化网络应用&#xff0c;动态改变本地IP地址的需求日益增多。本文将详细介绍如何安全、有效地实现这一目标&#xff0c;旨在帮…

Linux巡检利器xsos的安装和使用

一、 一般项目基本完成的时候&#xff0c;后期运维工作的重点就是及时的&#xff0c;合理的频率巡检了&#xff0c;巡检的目的主要是及时发现各种各样的问题 那么&#xff0c;自己编写shell脚本是大部分人的第一选择&#xff0c;这里有个比较麻烦的地方&#xff0c;shell脚本…

升级phpcmsV9系统的jquery版本引起的问题处理

前言&#xff1a; 如果jquery文件名修改了&#xff0c;/phpcms/modules/admin/templates/header.tpl.php文件中的jquery名称需要对应修改 一、后台输入框的验证问题 /statics/js/formvalidator.js文件调整为&#xff1a;点击下载 二、后台全选失效问题 1、/phpcms/modules/…

通过 Lighthouse 和 speed-measure-webpack 插件分析优化构建速度与体积

一、Lighthouse Lighthouse是 Google Chrome 推出的一款开源自动化工具&#xff0c;谷歌浏览器中已经集成&#xff0c;它可以搜集多个现代网页性能指标&#xff0c;分析 Web 应用的性能并生成报告&#xff0c;为开发人员进行性能优化的提供了参考方向。 Lighthouse会生成一份报…

Aatrox-Bert-VITS2部署指南

一、模型介绍 【AI 剑魔 ①】在线语音合成&#xff08;Bert-Vits2&#xff09;&#xff0c;将输入文字转化成暗裔剑魔亚托克斯音色的音频输出。 作者&#xff1a;Xz 乔希 https://space.bilibili.com/5859321 声音归属&#xff1a;Riot Games《英雄联盟》暗裔剑魔亚托克斯 …

分布式IO模拟量模块:多领域应用的高效能解决方案

分布式IO模拟量模块是分布式IO系统中的重要组件&#xff0c;用于实现现场设备或过程的模拟量信号的采集、监视和控制。该模块通常与现场总线耦合器配合使用&#xff0c;能够接收来自现场设备的模拟量信号&#xff08;如电流、电压等&#xff09;&#xff0c;并将其转换为数字信…

谷歌地图 | 与 Android 版导航 SDK 集成的最佳实践

谷歌最近宣布了导航 SDK&#xff0c;它可以让您将熟悉的 Google 地图逐向导航体验无缝集成到您的 Android 和 iOS 应用程序中。 这篇博文概述了一些最佳实践&#xff0c;您可以使用这些实践为您的 Android 应用程序使用导航 SDK 构建流畅、一致且可靠的导航体验。 与导航地图…

Linux系统安装软件的4种方式【源码配置编译安装、yum安装、rpm包安装、二进制软件包安装(.rpm/.tar.gz/.tgz/.bz2)】

一.源码安装 linux安装软件采用源码安装灵活自由&#xff0c;适用于不同的平台&#xff0c;维护也十分方便。 &#xff08;一&#xff09;源码安装流程  源码的安装一般由3个步骤组成&#xff1a; 1.配置&#xff08;configure&#xff09; Configure是一个可执行脚本…

5586 直播获奖(live)

经验值&#xff1a;1200 时间限制&#xff1a;1000毫秒 内存限制&#xff1a;256MB 全国2020CSP-J普及组试题 不许抄袭&#xff0c;一旦发现&#xff0c;直接清空经验&#xff01; 题目描述 Description NOI2130 即将举行。为了增加观赏性&#xff0c;CCF 决定逐一评出每个…

YOLOv11在目标检测中的应用及其与PaddleDetection的对比

近年来&#xff0c;目标检测模型在诸如自动驾驶、安全监控等应用中发挥了关键作用。众多模型中&#xff0c;YOLO&#xff08;You Only Look Once&#xff09; 系列凭借其在速度和精度之间的良好平衡脱颖而出。YOLOv11 作为该系列的最新版本之一&#xff0c;凭借其多项创新&…

Vue.js 入门教程

Vue.js 入门教程 一、引言 Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。与其他重量级框架不同&#xff0c;Vue 采用自底向上增量开发的设计。Vue 的核心库只关注视图层&#xff0c;并且非常容易上手&#xff0c;同时也很容易与其他库或已有项目整合。本文将引导…

FPGA秋招必看基础 | FPGA设计流程

关注&#x1f446; 望森FPGA &#x1f446; 查看更多FPGA资讯 这是望森的第 30 期分享 作者 | 望森 来源 | 望森FPGA 目录 摘要 1 明确需求、设计系统架构 2 RTL 输入 3 功能仿真&#xff08;Behavioral Simulation&#xff09; 4 综合&#xff08;Synthesis&#xff09;…

Qgis 开发初级 《符号化》

本章主要简介Qgis 的矢量图层的符号化。Qgis的符号化具体作用于每个图层&#xff0c;图层通过具体的方法设置符号化样式。 1、QgsFeatureRenderer Qgs的符号化类主要是QgsFeatureRenderer&#xff0c;这是一个抽象类&#xff0c;它派生出了许多类&#xff0c;如下所示。常用的…

self-supervised learning(BERT和GPT)

1芝麻街与NLP模型 我們接下來要講的主題呢叫做Self-Supervised Learning&#xff0c;在講self-supervised learning之前呢&#xff0c;就不能不介紹一下芝麻街&#xff0c;為什麼呢因為不知道為什麼self-supervised learning的模型都是以芝麻街的人物命名。 因為Bert是一個非常…

使用Bert+BiLSTM+CRF训练 NER任务

使用的数据集在这里E-Commercial NER Dataset / 电商NER数据集_数据集-阿里云天池 针对面向电商的命名实体识别研究&#xff0c;我们通过爬取搜集了淘宝商品文本的标题&#xff0c;并标注了4大类&#xff0c;9小类的实体类别。具体类型及实体数量如下 针对面向电商的命名实体…