首页 > 技术文章 > 代理模式

ningxinjie 2020-01-16 10:17 原文

直接与间接:
   人们对复杂的软件系统常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活、
满足特定需求的解决方案。    

 动机(Motivate):
    在面向对象系统中,有些对象由于某种原因(比如对象创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给使用者、或者系统结构带来很多麻烦。

    如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。
意图(Intent):
       为其他对象提供一种代理以控制对这个对象的访问。  -------《设计模式》GOF

生活中的例子:
       代理模式提供一个中介以控制对这个对象的访问。一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。

 

 代码实例:
    在软件系统 中,我们无时不在跨越障碍,当我们访问网络上一台计算机的资源时,我们正在跨越网络障碍,当我们去访问服务器上数据库时,我们又在跨越数据库访问障碍,同 时还有网络障碍。跨越这些障碍有时候是非常复杂的,如果我们更多的去关注处理这些障碍问题,可能就会忽视了本来应该关注的业务逻辑问题,Proxy模式有助于我们去解决这些问题。我们以一个简单的数学计算程序为例,这个程序只负责进行简单的加减乘除运算:

 

如果我们想访问远程计算机的时候,一些比较耗时的操作,我们可能不需要同步进行,或者需要进行其他的操作,如果我们每次调用的时候都写出来,代码将十分混乱。

  #region 要访问的远程计算机中的类
    public class ProcessControlComputer
    {
        public void Send(string message)
        {
            //通过此远程计算机发送给指定的人的操作
            //...
            Console.WriteLine(message+":发送成功");
        }
    }
    #endregion

 

 使用代理,解决这种耗时的操作,这里拿线程举例子

 #region 代理者
    public class Proxy
    {
        private ProcessControlComputer _processcontrolcomputer = new ProcessControlComputer();

        public void Send(string message)
        {
            Task.Run(()=> { _processcontrolcomputer.Send(message); });//使用线程操作耗时且无需返回值的远程操作
        }
    }
    #endregion

 

 static void Main(string[] args)
        {
            ProcessControlComputerProxy p = new ProcessControlComputerProxy();
            p.Send("代理者发送消息");
            Console.WriteLine("正常执行");
            Console.ReadKey();
        }

 

 

 

为了保证代理与远程类保持相同的方法,这里我们引出一个接口,让其分别实现(下方代码在Program写Send是为因为如果不这样在这里加个休眠,连续执行Send,会使得内部实例化的都是第二个Send),具体代码如下,要好好体会

为了更大的扩展,杰杰也引入了泛型,好好体会代码...

 #region 保持统一的接口
    public interface IControl
    {
        void Send<T>(string message) where T : IControl, new();
    }
    #endregion

 

  #region 代理者
    public class Proxy : IControl
    {
        private IControl _processcontrolcomputer;

        public void Send<T>(string message) where T : IControl, new()
        {
            _processcontrolcomputer = new T();//只要保证本次的这个实例是对的,就可以(连续执行可能会使得到第一次的该处还没执行,替换成第二处的,这个通过在上方Program中加Send方法,中加休眠来解决)
            Task.Run(() => { _processcontrolcomputer.Send<T>(message); });//使用线程操作耗时且无需返回值的远程操作
        }
    }
    #endregion
 #region 要访问的远程计算机中的类
    public class ProcessControlComputer : IControl
    {
        public void Send<T>(string message) where T : IControl, new()
        {
            //通过此远程计算机发送给指定的人的操作
            //...
            Console.WriteLine(message + ":发送成功到1");
        }
    }
    public class ProcessControlComputer2 : IControl
    {
        public void Send<T>(string message) where T : IControl, new()
        {
            //通过此远程计算机发送给指定的人的操作
            //...
            Console.WriteLine(message + ":发送成功到2");
        }
    }
    #endregion
 class Program
    {
        static void Main(string[] args)
        {
            Proxy p = new Proxy();
            Program program = new Program();
            program.Send<ProcessControlComputer>(p, "代理者发送消息");
            program.Send<ProcessControlComputer2>(p, "发发发");
            Console.WriteLine("正常执行");
            Console.ReadKey();
        }
        private void Send<T>(Proxy p, string message) where T : IControl, new()
        {
            p.Send<T>(message);//只要保证不要同时调用Send即可,给一个小小的时间间隔
            Thread.Sleep(30);
        }
    }

 

 

加油!

推荐阅读