设计模式的征途—13.代理(Proxy)模式

所谓代购,简单说来就是找人帮忙购买所需要的商品。代购分为两种类型,一种是因为在当地买不到某件商品,又或者是因为当地这件商品的价格比其他地区的贵,因此托人在其他地区甚至国外购买该商品,然后通过快递发货或直接携带回来。另一种则是消费者对想要购买的商品相关信息的缺乏,自己无法确定其实际价值,因此只好委托中介讲价或购买。在软件开发中,有一种设计模式可以提供与袋盖类似的功能,由于某些原因,客户端不想或者不能直接访问某个对象,此时可以通过一个称之为“代理”的第三者来实现间接访问,该方案对应的设计模式则被称为代理模式。

外观模式(Proxy) 学习难度:★★★☆☆ 使用频率:★★★★☆

一、收费商务查询系统的设计

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

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

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

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

  M公司开发人员通过分析,决定采用一种间接访问的方式来实现该商务信息查询系统的设计,在客户端对象和信息查询对象之间增加一个代理对象,让代理对象来实现验证和日志记录功能,而无须直接对原有的商务信息查询对象进行修改,如下图所示:

  这种设计方案即为代理模式,它为对象的访问提供了一种设计方案,而且具有多种不同的类型,应用相当广泛。

二、代理模式概述

2.1 代理模式简介

代理(Proxy)模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。

  可以看重,代理模式的重点就在于引入了一个新的代理对象,代理对象可以在客户端对象和目标对象之间起到中介的作用,去掉客户不能看到的内容和服务或者添加客户需要的额外服务。

2.2 代理模式结构

  代理模式主要包含以下3个角色:

  (1)Subject(抽象主题角色):声明真实主题和代理主题的共同接口,使得在任何使用真实主题的地方都可以使用代理主题。

  (2)Proxy(代理主题角色):代理主题角色内部包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;

  (3)RealSubject(真实主题角色):定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作。

三、实现收费商务查询系统

3.1 系统设计结构

3.2 具体代码实现

  (1)抽象主题 => ISearcher接口

    /// <summary>
    /// 抽象主题类:抽象查询接口
    /// </summary>
    public interface ISearcher
    {
        string DoSearch(string userID, string keyword);
    }

  (2)真实主题 => RealSearcher类

    /// <summary>
    /// 真是主题类:具体查询器
    /// </summary>
   public  class RealSearcher
    {
        /// <summary>
        /// 模拟查询商务信息
        /// </summary>
        /// <returns></returns>
        public string DoSearch(string userID, string keyword)
        {
            Console.WriteLine("{0} 使用关键词 {1}", userID, keyword);
            return "返回具体内容";
        }
    }

  此外,还有两个业务类:AccessValidator用于验证用户身份,Logger则用于记录日志。

    /// <summary>
    /// 业务类:身份验证类
    /// </summary>
    public class AccessValidator
    {
        /// <summary>
        /// 模拟实现登录验证
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool Validate(string userID)
        {
            Console.WriteLine("在数据库中验证用户 {0} 是否是合法用户?", userID);
            if (userID.Equals("杨过", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("{0} 登录成功!", userID);
                return true;
            }
            else
            {
                Console.WriteLine("{0} 登录失败!", userID);
                return false;
            }
        }
    }

    /// <summary>
    /// 业务类:日志记录类
    /// </summary>
    public class Logger
    {
        /// <summary>
        /// 模拟实现日志记录
        /// </summary>
        /// <param name="userID"></param>
        public void Log(string userID)
        {
            Console.WriteLine("更新数据库,用户 {0} 查询次数加1!", userID);
        }
    }

  (3)代理主题 => ProxySearcher类

    /// <summary>
    /// 代理主题类:代理查询
    /// </summary>
    public class ProxySearcher : ISearcher
    {
        private RealSearcher searcher = new RealSearcher(); // 维持一个对真实主题的引用
        private AccessValidator validator;
        private Logger logger;

        public string DoSearch(string userID, string keyword)
        {
            if (Validate(userID))
            {
                string result = searcher.DoSearch(userID, keyword);
                this.Log(userID);
                return result;
            }

            return null;
        }

        /// <summary>
        /// 创建访问验证对象并调用其Validate()方法进行身份验证
        /// </summary>
        /// <returns></returns>
        public bool Validate(string userID)
        {
            validator = new AccessValidator();
            return validator.Validate(userID);
        }

        /// <summary>
        /// 创建日志记录器并调用Log()方法实现日志记录
        /// </summary>
        /// <param name="userID"></param>
        public void Log(string userID)
        {
            logger = new Logger();
            logger.Log(userID);
        }
    }

  (4)客户端调用

  ① 为了提高系统可扩展性,这里将代理主题类存在了配置文件中

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <!-- Proxy Setting -->
    <add key="ProxyName" value="Manulife.ChengDu.DesignPattern.Proxy.ProxySearcher, Manulife.ChengDu.DesignPattern.Proxy" />
  </appSettings>
</configuration>

  ② 客户端调试代码

    public class Program
    {
        public static void Main(string[] args)
        {
            ISearcher searcher = AppConfigHelper.GetProxyInstance() as ISearcher;
            if (searcher != null)
            {
                string result = searcher.DoSearch("杨过", "玉女心经");
            }

            Console.ReadKey();
        }
    }

  这里AppConfigHelper主要用于访问配置文件并通过反射生成实例对象

    public class AppConfigHelper
    {
        public static string GetProxyName()
        {
            string factoryName = null;
            try
            {
                factoryName = System.Configuration.ConfigurationManager.AppSettings["ProxyName"];
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return factoryName;
        }

        public static object GetProxyInstance()
        {
            string assemblyName = AppConfigHelper.GetProxyName();
            Type type = Type.GetType(assemblyName);

            var instance = Activator.CreateInstance(type);
            return instance;
        }
    }

  ③ 运行结果

  

四、代理模式总结

4.1 主要优点

  (1)协调了调用者和被调用者,一定程度上降低了系统的耦合度 => 符合迪米特法则

  (2)客户端针对抽象主题角色编程,增加和更换代理类无须修改源代码 => 符合开闭原则

4.2 应用场景

  (1)客户端需要访问远程主机中的对象时 => 远程代理

  (2)需要一个消耗资源较少的对象来代表一个消耗资源较多的对象 => 降低系统开销

  (3)需要控制对一个对象的访问,为不同用户提供不同级别的访问权限 => 保护代理

参考资料

  

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

时间: 2024-12-27 10:23:01

设计模式的征途—13.代理(Proxy)模式的相关文章

设计模式 之代理(Proxy)模式

为什么这里要定义代理呢?所谓代理代理,当然就是你不想做的事,找别人去做,这就是代理.所以,当你写代码的时候,你想保持类的简单性.重用性,你就可以把事件尽量都交给其它类去做,自己只管做好自己的事.也就是SRP,单一职责原则.如果一个类关注的点过多,做的事情太多.这些事情不管是你直接做的,还是调用别的对象去完成的.这都不行,自己做这些事,那就会使类的功能复杂化,维护不方便.而过多地调用其它对象来完成一些事情,表面上看起来好像不错,实际上是过度耦合了.我们编写类的原则应该是追求高内聚,低耦合的.可能你

Android中的代理(Proxy)模式

一. Proxy模式定义 Proxy模式,也称代理模式,是经典设计模式中的一种结构型模式,其定义是为其他对象提供一种代理以控制对这个对象的访问,简单的说就是在访问和被访问对象中间加上的一个间接层,以隔离访问者和被访问者的实现细节. 二. Proxy模式理解 当无法或者不想直接访问某个对象, 或者访问某个对象存在困难时, 可以通过一个代理对象来间接访问, 为了保证客户端使用的透明性, 委托对象与代理对象需要实现相同的接口. 例如,ActivityManager 作为客户端要访问 AMS,AMS 不

设计模式--代理(Proxy)模式

在公司,经常性听到采购部的人说采购某样东材料,采购不了,需要通过代理商才可以.以前Insus.NET也做有一个练习<找人办事,代理设计模式(Proxy)>http://www.cnblogs.com/insus/archive/2013/02/27/2935081.html .理解起来跟公司的采购员找代理商采购是一样的道理. 统一的行为,就是采购,不管是公司的采购员还是代理商: 公司的采购员: 代理商: OK,实现环境: 演示: 代理模式实际环境中很多.比如我们想租或买房,均可以让代码帮助我们

Android与设计模式——代理(Proxy)模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述代理(Proxy)模式的: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式的结构. 所谓代理,就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式类图如下: 在代理模式中的角色: ●抽象对象角色(Phone):声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象

行为模式--代理Proxy模式(Java)

代理(AOP切面的雏形): 题记:顾名思义就是将某件事,某个东西的使用权进行为让授权转移.代理相当于中介(不同于中介者模式),在原本操作的类之间添加了一个桥梁.但代理不能去修改原有目标.比如:一个人要买       房,让中介帮忙给看个房,但中介不能将原有看房这件事变更为看车.他可以对看房提出各种要求和咨询. 回到程序的角度,调用者将调用某些共性类的处理交由代理类处理,代理类根据调用者的要求即满足什么情况可以调用,什么情况不能调用,(卖房者委托中介100万以上卖,100万以下不卖)对处理做前后的

代理(Proxy)模式

代理模式的类图如下所示: 客户端想调用的是RealSubject,由于某种考虑或原因,只能直接访问到ProxySubject,再由ProxySubject去调用RealSubject,这就完成了一次代理的活动. 代理模式的时序图如下: 从上面可以看出,ProxySubject不仅可以完成对RealSubject的调用,在调用前后还可以完成一些事情,这就是代理模式的优点. 代理模式按照使用的分类,可以分为以下几类: 远程代理:为一个不同地址空间的对象提供一个局域代表对象. 虚拟代理:根据需求创建一

Java 实现代理(Proxy)模式

/** * 游戏者接口 * @author stone * */ public interface IGamePlayer { // 登录游戏 public void login(String user, String password); // 杀怪,网络游戏的主要特色 public void killBoss(); // 升级 public void upgrade(); } /** * 游戏者 * @author stone * */ public class GamePlayer imp

单点登录cas常见问题(八) - 什么时候会用到代理proxy模式?

举一个样例:有两个应用App1和App2,它们都是受Casserver保护的,即请求它们时都须要通过Cas server的认证. 如今须要在App1中通过Http请求訪问App2,显然该请求将会被App2配置的Cas的AuthenticationFilter拦截并转向Cas server,Casserver将引导用户进行登录认证,这样我们也就訪问不到App2的资源了. 针对这样的应用场景.Cas也提供了Cas Proxy 轻松的攻克了这个问题.

设计模式的征途—文章目录索引

1.预备篇 UML类图10分钟快速入门 2.创建型模式 ① 设计模式的征途-01.单例(Singleton)模式 ② 设计模式的征途-02.简单工厂(Simple Factory)模式 ③ 设计模式的征途-03.工厂方法(Factory Method)模式 ④ 设计模式的征途-04.抽象工厂(Abstract Factory)模式 ⑤ 设计模式的征途-05.原型(Prototype)模式 ⑥ 设计模式的征途-06.建造者(Builder)模式 3.结构型模式 ① 设计模式的征途-07.适配器(A