代理模式(Proxy)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 转载 https://blog.csdn.net/lovelion/article/details/8228042某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:(1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;(2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。

转载 https://blog.csdn.net/lovelion/article/details/8228042

某软件公司承接了某信息咨询公司的收费商务信息查询系统的开发任务,该系统的基本需求如下:

(1) 在进行商务信息查询之前用户需要通过身份验证,只有合法用户才能够使用该查询系统;

(2) 在进行商务信息查询时系统需要记录查询日志,以便根据查询次数收取查询费用。

该软件公司开发人员已完成了商务信息查询模块的开发任务,现希望能够以一种松耦合的方式向原有系统增加身份验证和日志记录功能,客户端代码可以无区别地对待原始的商务信息查询模块和增加新功能之后的商务信息查询模块,而且可能在将来还要在该信息查询模块中增加一些新的功能。

试使用代理模式设计并实现该收费商务信息查询系统。

  1. 实例分析及类图

通过分析,可以采用一种间接访问的方式来实现该商务信息查询系统的设计,在客户端对象和信息查询对象之间增加一个代理对象,让代理对象来实现身份验证和日志记录等功能,而无须直接对原有的商务信息查询对象进行修改,如图1-1所示:

img_d2852ee7a9d0ed4f38b28a5d958d1005.png
1-1.png

在图中,客户端对象通过代理对象间接访问具有商务信息查询功能的真实对象,在代理对象中除了调用真实对象的商务信息查询功能外,还增加了身份验证和日志记录等功能。使用代理模式设计该商务信息查询系统,结构图如图1-2所示。

img_ce723fadae8ab748ca576b6d91564431.png
1-2.png

在图1-2中,业务类AccessValidator用于验证用户身份,业务类Logger用于记录用户查询日志,Searcher充当抽象主题角色,RealSearcher充当真实主题角色,ProxySearcher充当代理主题角色

  1. 实例代码
    (1) AccessValidator:身份验证类,业务类,它提供方法Validate()来实现身份验证。

//AccessValidator.cs
using System;
 
namespace ProxySample
{
    class AccessValidator
    {
        //模拟实现登录验证
        public bool Validate(string userId) 
        {
            Console.WriteLine("在数据库中验证用户'" + userId + "'是否是合法用户?");
            if (userId.Equals("杨过")) {
                Console.WriteLine("'{0}'登录成功!",userId);
                return true;
            }
            else {
                Console.WriteLine("'{0}'登录失败!", userId);
                return false;
            }
        }
    }

(2) Logger:日志记录类,业务类,它提供方法Log()来保存日志。


//Logger.cs
using System;
 
namespace ProxySample
{
    class Logger
    {
        //模拟实现日志记录
        public void Log(string userId) {
            Console.WriteLine("更新数据库,用户'{0}'查询次数加1!",userId);
        }
    }
}

(3) Searcher:抽象查询类,充当抽象主题角色,它声明了DoSearch()方法。


namespace ProxySample
{
    interface Searcher
    {
        string DoSearch(string userId, string keyword);
    }
}

(4) RealSearcher:具体查询类,充当真实主题角色,它实现查询功能,提供方法DoSearch()来查询信息。


//RealSearcher.cs
using System;
 
namespace ProxySample
{
    class RealSearcher : Searcher
    {
        //模拟查询商务信息
        public string DoSearch(string userId, string keyword) {
            Console.WriteLine("用户'{0}'使用关键词'{1}'查询商务信息!",userId,keyword);
            return "返回具体内容";
        }
    }
}

(5) ProxySearcher:代理查询类,充当代理主题角色,它是查询代理,维持了对RealSearcher对象、AccessValidator对象和Logger对象的引用。


namespace ProxySample
{
    class ProxySearcher : Searcher
    {
        private RealSearcher searcher = new RealSearcher(); //维持一个对真实主题的引用
        private AccessValidator validator;
        private Logger logger;
 
        public string DoSearch(string userId, string keyword)
        {
            //如果身份验证成功,则执行查询
            if (this.Validate(userId))
            {
                string result = searcher.DoSearch(userId, keyword); //调用真实主题对象的查询方法
                this.Log(userId); //记录查询日志
                return result; //返回查询结果
            }
            else
            {
                return null;
            }
        }
 
        //创建访问验证对象并调用其Validate()方法实现身份验证
        public bool Validate(string userId)
        {
            validator = new AccessValidator();
            return validator.Validate(userId);
        }
 
        //创建日志记录对象并调用其Log()方法实现日志记录
        public void Log(string userId)
        {
            logger = new Logger();
            logger.Log(userId);
        }
    }
}

(6) 配置文件App.config,在配置文件中存储了代理主题类类名。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="proxy" value="ProxySample.ProxySearcher"/>
  </appSettings>
</configuration>

(7) Program:客户端测试类

//Program.cs
using System;
using System.Configuration;
using System.Reflection;
 
namespace ProxySample
{
    class Program
    {
        static void Main(string[] args)
        {
            //读取配置文件
            string proxy = ConfigurationManager.AppSettings["proxy"];
 
            //反射生成对象,针对抽象编程,客户端无须分辨真实主题类和代理类
            Searcher searcher;
            searcher = (Searcher)Assembly.Load("ProxySample").CreateInstance(proxy);
 
            String result = searcher.DoSearch("杨过", "玉女心经");
            Console.Read();
        }
    }
}

结果及分析

在数据库中验证用户'杨过'是否是合法用户?
'杨过'登录成功!
用户'杨过'使用关键词'玉女心经'查询商务信息!
更新数据库,用户'杨过'查询次数加1!

本实例是保护代理和智能引用代理的应用实例,在代理类ProxySearcher中实现对真实主题类的权限控制和引用计数,如果需要在访问真实主题时增加新的访问控制机制和新功能,只需增加一个新的代理类,再修改配置文件,在客户端代码中使用新增代理类即可,源代码无须修改,符合开闭原则。

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
3月前
|
存储 虚拟化 iOS开发
VMware ESXi 9.0 macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版
VMware ESXi 9.0 macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版
501 1
VMware ESXi 9.0 macOS Unlocker & OEM BIOS 2.7 标准版和厂商定制版
|
网络安全 Nacos 数据安全/隐私保护
nacos常见问题之使用默认用户名密码提示错误如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
|
算法 数据安全/隐私保护 Python
维吉尼亚加密算法【python】
维吉尼亚加密算法【python】
355 1
|
机器学习/深度学习 前端开发 JavaScript
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
243 0
源映射错误:Error: request failed with status 404 源 URL:http://localhost:8080/bootstrap/js/axios-0.18.0.js
|
11月前
|
前端开发 JavaScript API
React 搜索组件 Search Box
本文介绍了如何在 React 中实现一个搜索组件,从基础的输入框和按钮创建开始,逐步讲解样式美化、常见问题及易错点的解决方法,包括输入延迟、空值处理、错误处理和状态管理等,帮助开发者构建高效、可靠的搜索功能。
523 4
|
前端开发 JavaScript Java
毕业设计|基于SSM框架的毕业设计管理系统
毕业设计|基于SSM框架的毕业设计管理系统
220 0
|
Ubuntu 网络虚拟化 Windows
国产化之虚拟ARM64-CPU安装银河麒麟操作系统
国产化之虚拟ARM64-CPU安装银河麒麟操作系统
2737 0
|
运维 安全 关系型数据库
GTID 入门
从MySQL 5.6.5 开始新增了一种基于 GTID 的复制方式。通过 GTID 保证了每个在主库上提交的事务在集群中有一个唯一的ID。这种方式强化了数据库的主备一致性,故障恢复以及容错能力。
353 0
|
运维 Cloud Native 安全
重磅 | 阿里云发布AnalyticDB数仓升舱解决方案 可帮客户节省50% IT采购成本
7月19日,在今日召开的“升舱计划实战峰会”上,阿里云发布AnalyticDB数据仓库升舱解决方案,可帮助金融、电信等行业客户实现传统数仓向云原生数据仓库的平滑升级,在IT采购成本(软件+硬件) 降低约50%的同时,复杂查询性能从分钟级缩减至秒级
重磅 | 阿里云发布AnalyticDB数仓升舱解决方案 可帮客户节省50% IT采购成本
|
应用服务中间件 Shell
Tomcat 的单机多实例配置
Tomcat 的单机多实例配置
173 0
Tomcat 的单机多实例配置