委托通常可以应用到哪些场合

分析问题

  委托的功能和其名字非常类似,在设计中其思想在于把工作委派给其他特定的类型或者组件。委托的使用者可以理解为工作的分派者,在通常情况下使用者清楚地知道哪些工作需要执行、执行的结果又是什么,但是他却不会亲自地去做这些工作,而是恰当地把这些工作分派出去。

  在本节中,笔者将举一个日志读写的例子,来说明委托的实际应用。日志子系统在几乎所有的系统中都有所应用,在一般情况下,日志子系统的使用者希望的都是一个单一的方法,传入日志内容和日志类型,而日志系统会根据具体情况来进行写日志动作。对于日志系统的设计者来说,写一条日志可能需要包含一系列的工作,而日志系统决定把这些工作进行恰当的分派,这时就需要使用一个委托成员。下面代码展示了这个日志系统的简单实现方式。

using System;
using System.IO;
using System.Text;

namespace Test
{
    /// <summary>
    /// Log的类别
    /// </summary>
    public enum LogType
    {
        Debug,
        Trace,
        Info,
        Warn,
        Error,

    }

    /// <summary>
    /// Log委托类型,由日志使用者直接执行来完成写日志的工作
    /// </summary>
    /// <param name="content"></param>
    /// <param name="type"></param>
    public delegate void Log(string content,LogType type);

    public sealed partial class LogManager:IDisposable
    {
        //书写日志的组件
        private Type _componentType;
        //日志文件
        private string _logFile;
        //日志文件读写流
        private FileStream _fs;
        //用来写日志的委托
        public Log writeLog;
        //锁
        private static object mutext = new object();

        public LogManager()
        {
            writeLog = new Log(PreppareLogFile);
            writeLog += OpenStream;

            writeLog += AppendLocalTime;
            writeLog += AppendSeperator;
            writeLog += AppendComponentType;
            writeLog += AppendSeperator;
            writeLog += AppendType;
            writeLog += AppendSeperator;
            writeLog += AppendContent;
            writeLog += AppendNewLine;
            writeLog += CloseStream;
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="type">使用该日志的类型</param>
        /// <param name="file">日志文件全路径</param>
        public LogManager(Type type, string file)
            : this()
        {
            _logFile = file;
            _componentType = type;
        }

        /// <summary>
        /// 释放FileStream对象
        /// </summary>
        public void Dispose()
        {
            if (_fs!=null)
            {
                _fs.Dispose();
            }
            GC.SuppressFinalize(this);
        }

        ~LogManager()
        {
            if (_fs!=null)
            {
                _fs.Dispose();
            }
        }

        #region 和日志文件有关的操作

        /// <summary>
        /// 如果日志文件不存在,则新建日志文件
        /// </summary>
        private void PreppareLogFile(string content, LogType type)
        {
            //只允许单线程创建日志文件
            lock (mutext)
            {
                if (File.Exists(_logFile)==false)
                {
                    using (FileStream fs = File.Create(_logFile))
                    {

                    }
                }
            }
        }

        /// <summary>
        /// 打开文件流
        /// </summary>
        private void OpenStream(string content, LogType type)
        {
            _fs = File.Open(_logFile, FileMode.Append);
        }

        /// <summary>
        /// 关闭文件流
        /// </summary>
        private void CloseStream(string content, LogType type)
        {
            _fs.Close();
            _fs.Dispose();
        }

        #endregion

        #region 和时间记录有关的操作

        /// <summary>
        /// 为日志添加当前UTC时间
        /// </summary>
        private void AppendUTCTime(string content, LogType type)
        {
            //得到当前UTC时间
            string time = DateTime.Now.ToUniversalTime().ToString();
            byte[] con = Encoding.Default.GetBytes(time);
            _fs.Write(con, 0, con.Length);
        }

        /// <summary>
        /// 为日志添加本地时间
        /// </summary>
        private void AppendLocalTime(string content, LogType type)
        {
            //得到本地时间
            string time = DateTime.Now.ToLocalTime().ToString();
            byte[] con = Encoding.Default.GetBytes(time);
            _fs.Write(con, 0, con.Length);
        }

        #endregion

        #region 和日志内容有关的操作

        /// <summary>
        /// 添加日志内容
        /// </summary>
        private void AppendContent(string content, LogType type)
        {
            byte[] con = Encoding.Default.GetBytes(content);
            _fs.Write(con, 0, con.Length);
        }

        /// <summary>
        /// 为日志添加组件类型
        /// </summary>
        private void AppendComponentType(string content, LogType type)
        {
            byte[] con = Encoding.Default.GetBytes(_componentType.ToString());
            _fs.Write(con, 0, con.Length);
        }

        /// <summary>
        /// 添加日志类型
        /// </summary>
        private void AppendType(string content, LogType type)
        {
            string typeString = string.Empty;
            switch (type)
            {
                    //针对不同的日志类型来记录
                case LogType.Debug:
                    typeString = "Debug";
                    break;
                case LogType.Trace:
                    typeString = "Trace";
                    break;
                case LogType.Info:
                    typeString = "Info";
                    break;
                case LogType.Warn:
                    typeString = "Warn";
                    break;
                case LogType.Error:
                    typeString = "Error";
                    break;
                default:
                    typeString = "";
                    break;
            }
            byte[] con = Encoding.Default.GetBytes(typeString);
            _fs.Write(con, 0, con.Length);
        }

        #endregion

        #region 和日志格式控制有关的操作

        /// <summary>
        /// 添加分隔符
        /// </summary>
        private void AppendSeperator(string content, LogType type)
        {
            byte[] con = Encoding.Default.GetBytes(" | ");
            _fs.Write(con, 0, con.Length);
        }

        /// <summary>
        /// 添加换行符
        /// </summary>
        private void AppendNewLine(string content, LogType type)
        {
            byte[] con = Encoding.Default.GetBytes("\r\n");
            _fs.Write(con, 0, con.Length);
        }

        #endregion

        #region 修改所使用的时间类型

        /// <summary>
        /// 设置使用UTC时间
        /// </summary>
        public void UseUTCTime()
        {
            writeLog = new Log(PreppareLogFile);
            writeLog += OpenStream;
            //这里添加记录UTC时间的方法
            writeLog += AppendUTCTime;
            writeLog += AppendSeperator;
            writeLog += AppendComponentType;
            writeLog += AppendSeperator;
            writeLog += AppendType;
            writeLog += AppendSeperator;
            writeLog += AppendContent;
            writeLog += AppendNewLine;
            writeLog += CloseStream;
        }

        /// <summary>
        /// 设置使用本地时间
        /// </summary>
        public void UseLocalTime()
        {
            writeLog = new Log(PreppareLogFile);
            writeLog += OpenStream;
            //这里添加记录本地时间的方法
            writeLog += AppendLocalTime;
            writeLog += AppendSeperator;
            writeLog += AppendComponentType;
            writeLog += AppendSeperator;
            writeLog += AppendType;
            writeLog += AppendSeperator;
            writeLog += AppendContent;
            writeLog += AppendNewLine;
            writeLog += CloseStream;
        }

        #endregion

    }
    class UseLog
    {
        /// <summary>
        /// 使用日志管理类型来记录日志
        /// </summary>
        static void Main()
        {
            //使用日志
            using (LogManager logManager = new LogManager(Type.GetType("Test.UseLog"), @"D:\TestLog.txt"))
            {
                //记录日志
                logManager.writeLog("新建了日志", LogType.Debug);
                logManager.writeLog("写数据", LogType.Debug);
                logManager.UseUTCTime();
                logManager.writeLog("现在是UTC时间", LogType.Debug);
                logManager.UseLocalTime();
                logManager.writeLog("现在是本地时间", LogType.Debug);
                logManager.writeLog("发生错误", LogType.Error);
                logManager.writeLog("准备退出", LogType.Info);

            }
        }
    }
}

  在上述代码所示的Log子系统中,使用了一个Log类型的委托来做所有的日志工作,而LogManager只需要管理这个委托,负责分派任务即可。代码中初始化委托成员的过程即是任务分派的过程,读者可能已经注意到,LogManager的UseUTCTime和UseLocalTime方法都对委托成员进行了重新分配,这可以理解为任务的再分配。

说明

  委托作为日志子系统的另一优点就在于可以灵活地分派任务,并且随时可以重新整理。读者可以尝试为LogManager添加其他功能,例如尝试提供其他编码的日志,并且提供重分配的公共方法来让使用者进行选择。

  下面是以上代码执行后的日志输出:

  

  

答案

  委托的应用场合通常是任务的执行者把细节工作进行再分配,执行者确切地知道什么工作将要被执行,但却把执行细节委托给其他组件、方法或者程序集。

时间: 2024-08-25 21:32:11

委托通常可以应用到哪些场合的相关文章

.NET基础 (15)委托

委托1 请解释委托的基本原理2 委托回调静态方法和实例方法有何区别3 什么是链式委托4 链式委托的执行顺序是怎么样的5 可否定义拥有返回值的方法的委托链6 委托通常可以应用在哪些场合 委托1 请解释委托的基本原理 委托是一个钟数据类型,用来传递方法.委托类型继承自System.Delegate,自定义委托类型都直接继承自System.NulticastDelegate,System.NulticastDelegate又继承自System.Delegate.每个委托至少包含一个指向某个方法的指针,

实现基于Task的异步模式

返回该系列目录<基于Task的异步模式--全面介绍> 生成方法 编译器生成 在.NET Framework 4.5中,C#编译器实现了TAP.任何标有async关键字的方法都是异步方法,编译器会使用TAP执行必要的转换从而异步地实现方法.这样的方法应该返回Task或者Task<TResult>类型.在后者的案例中,方法体应该返回一个TResult,且编译器将确保通过返回的Task<TResult>是可利用的.相似地,方法体内未经处理的异常会被封送到输出的task,造成返

Task的异步模式

Task的异步模式 返回该系列目录<基于Task的异步模式--全面介绍> 生成方法 编译器生成 在.NET Framework 4.5中,C#编译器实现了TAP.任何标有async关键字的方法都是异步方法,编译器会使用TAP执行必要的转换从而异步地实现方法.这样的方法应该返回Task或者Task<TResult>类型.在后者的案例中,方法体应该返回一个TResult,且编译器将确保通过返回的Task<TResult>是可利用的.相似地,方法体内未经处理的异常会被封送到输

摘录-IT企业必读的200个.NET面试题-06 .NET中的高级特性

委托 Q: 请解释委托的基本原理 委托是一类继承自System.Delegate的类型,每个委托对象至少包含了一个指向某个方法的指针,委托实现了回调方法的机制. Q: 委托回调静态方法和实例方法的区别 当委托绑定静态方法时,内部的对象成员变量_target将会被设置为null,而当委托绑定实例方法时,_target将会设置成指向该实例方法所属类型的一个实例对象,当委托被执行时,该对象实例将被用来调用实例方法. Q: 什么是链式委托 链式委托是指一个由委托串成的链表,当链表上的一个委托被回调时,所

JAVA学习篇--静态代理VS动态代理

本篇博客的由来,之前我们学习大话设计,就了解了代理模式,但为什么还要说呢? 原因: 1,通过DRP这个项目,了解到了动态代理,认识到我们之前一直使用的都是静态代理,那么动态代理又有什么好处呢?它们二者的区别是什么呢? 2,通过学习动态代理了解到动态代理是一种符合AOP设计思想的技术,那么什么又是AOP? 下面是我对它们的理解! 代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对

java静态代理和动态代理(一)

代理Proxy: Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题. 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别.通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从

js事件冒泡和事件委托

js所谓的事件冒泡就是子级元素的某个事件被触发,它的上级元素的该事件也被递归执行 html: 1 <ul class="clearfix" data-type="cityPick"> 2 <li class="active_sort_opts" data-id="0">全部</li> 3 <li data-id="88">纽约</li> 4 <

android深入之设计模式(一)委托模式

(一)委托模式简介 委托模式是基本的设计模式之一.委托,即是让另一个对象帮你做事情. 许多其他的模式,如状态模式.策略模式.访问者模式本质上是在更特殊的场合采用了委托模式. 委托模式使得我们可以用聚合来替代继承,java-组合优于继承. 最简单的java委托模式 class RealPrinter { void print() { System.out.println("real printer"); } } class Printer { RealPrinter realPrinte

C++:关于委托类

转自:http://blog.csdn.net/dadalan/article/details/4041931.vs2010已经支持function/bind,能很好实现委托. [说明] 本文不仅介绍了C++语言应用非常好的一种方法(我甚至觉得应该将它归结为一种设计模式),而且也是对C#语言中委托特性底层实现的一个很好的说明. 阅读本文,你应当对委托的概念有所了解:在讨论委托是实现时,你应当对标准模板库(STL)中的list容器以及迭代器(iterator)有所了解. 在这篇文章中,暂不讨论类成