代理模式(Proxy)

简介: 转载 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中实现对真实主题类的权限控制和引用计数,如果需要在访问真实主题时增加新的访问控制机制和新功能,只需增加一个新的代理类,再修改配置文件,在客户端代码中使用新增代理类即可,源代码无须修改,符合开闭原则。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
3月前
|
设计模式 C#
设计模式之代理模式(Proxy)
设计模式之代理模式(Proxy)
|
6月前
|
设计模式 安全 Java
设计模式~代理模式(Proxy)-17
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。 【跟MM在网上聊天,一开头总是“hi, 你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这
33 0
|
11月前
|
设计模式 SQL 安全
Java设计模式-代理模式(Proxy)
Java设计模式-代理模式(Proxy)
|
Arthas Java 测试技术
结构型模式 - 代理模式(Proxy Pattern)
结构型模式 - 代理模式(Proxy Pattern)
|
存储 设计模式 Java
Proxy动态代理机制详解
代理模式给某一个(目标)对象提供一个代理对象,并由代理对象持有目标对象的引用,所谓代理,就是一个对象代表另一个对象执行相应的动作程序。
78 0
Proxy动态代理机制详解
|
设计模式 Java
设计模式-Proxy代理模式
设计模式-Proxy代理模式
设计模式-Proxy代理模式
|
设计模式 缓存 监控
结构型-Proxy
代理模式(Proxy Design Pattern)的原理和代码实现都不难掌握。它在不改变原始类(或叫被代理类)代码的情况下,通过引入代理类来给原始类附加功能。 1. 代理模式的原理与实现 在不改变原始类(或叫被代理类)的情况下,通过引入代理类来给原始类附加功能。一般情况下,我们让代理类和原始类实现同样的接口。但是,如果原始类并没有定义接口,并且原始类代码并不是我们开发维护的。在这种情况下,我们可以通过让代理类继承原始类的方法来实现代理模式。
123 0
|
设计模式 安全 Java
【Java设计模式】代理模式(Proxy Pattern)
为其他对象提供一种代理,以控制对这个对象的访问,代理对象在客户端和目标对象之间起到中介作用。
112 0
【Java设计模式】代理模式(Proxy Pattern)
|
设计模式 缓存 Java
浅谈JAVA设计模式之——代理模式(proxy)
为其他对象提供一种代理以控制对这个对象的访问。
109 0
浅谈JAVA设计模式之——代理模式(proxy)