我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)

回到目录

之前的讲过两篇关于日志组件的文章,分别是《第一回  日志记录组件之自主的Vlog》和《第三回  日志记录组件之log4net》,而今天主要说一下我自己开发的另一种日志组件Logger.Core,它也属于面试AOP(横切关注点)的一部分,这个组件对于一些想学习设计模式的同学来说,无疑是一个大餐!Logger.Core项目里内含了策略模式模版方法模式工厂模式单例模式,可以说,最常用的模式都用到了,而它们在这个项目里都起到了什么作用,什么时候用到它们呢,这些答案相信在看完我的文章之后,您会有一个明确的答案的。

一 面向接口编程与多态

面向接口编程,是实现软件解耦的灵魂,也是实现多态的方法之一,日志项目有统一的接口规范

我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
    /// <summary>

    /// 日志功能接口规范

    /// </summary>

    public interface ILogger

    {

        /// <summary>

        /// 记录代码运行时间

        /// </summary>

        /// <param name="message">消息</param>

        /// <param name="action">所测试的代码块</param>

        /// <param name="fileName">日志文件名</param>

        void Logger_Timer(string message, Action action, string fileName);



        /// <summary>

        /// 记录代码运行时间,日志文件名以codeTime开头的时间戳

        /// </summary>

        /// <param name="message">消息</param>

        /// <param name="action">所测试的代码块</param>

        void Logger_Timer(string message, Action action);



        /// <summary>

        /// 记录代码运行异常

        /// </summary>

        /// <param name="message">消息</param>

        /// <param name="action">要添加try...catch的代码块</param>

        /// <param name="fileName">日志文件名</param>

        void Logger_Exception(string message, Action action, string fileName);



        /// <summary>

        /// 记录代码运行异常,日志文件名以Exception开头的时间戳

        /// </summary>

        /// <param name="message">消息</param>

        /// <param name="action">要添加try...catch的代码块</param>

        void Logger_Exception(string message, Action action);



        /// <summary>

        /// 将message记录到日志文件

        /// </summary>

        /// <param name="message"></param>

        void Logger_Info(string message);



        /// <summary>

        /// 将message记录到名为fileName的日志文件

        /// </summary>

        /// <param name="message"></param>

        /// <param name="fileName"></param>

        void Logger_Info(string message, string fileName);

    }
View Code

二 继承与面向对象

继承是面向对象的三大特性之一,有了它,面向对象才有了层次感,将公共的功能点从各个派生类抽出,提取到基类中

我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
    /// <summary>

    /// 日志核心基类

    /// 模版方法模式,对InputLogger开放,对其它日志逻辑隐藏,InputLogger可以有多种实现

    /// </summary>

    internal abstract class LoggerBase : ILogger

    {

        private string _defaultLoggerName = DateTime.Now.ToString("yyyyMMddhh") + ".log";



        /// <summary>

        /// 日志文件地址

        /// 优化级为mvc方案地址,网站方案地址,console程序地址

        /// </summary>

        protected string FileUrl

        {

            get

            {

                try

                {



                    return System.Web.HttpContext.Current.Server.MapPath("/Logger/"

                          + System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()

                          + "/"

                          + System.Web.HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString()

                          + "/"); //例如:c:\\project\\Logger\\Home\\Index\\

                }

                catch (NullReferenceException)

                {

                    try

                    {

                        return System.Web.HttpRuntime.AppDomainAppPath + "LoggerDir\\"; //例如:c:\\project\\

                    }

                    catch (ArgumentNullException)

                    {



                        return Environment.CurrentDirectory + "\\LoggerDir\\"; //例如:c:\\project\\bin\\debug

                    }



                }

            }

        }



        protected abstract void InputLogger(string message, string fileName);



        #region ILogger 成员



        public void Logger_Timer(string message, Action action, string fileName)

        {

            StringBuilder str = new StringBuilder();

            Stopwatch sw = new Stopwatch();

            sw.Restart();

            str.Append(message);

            action();

            str.Append("代码段运行时间:" + sw.ElapsedMilliseconds + "毫秒");

            InputLogger(str.ToString(), string.IsNullOrWhiteSpace(fileName)

                ? "CodeTime" + _defaultLoggerName

                : fileName);

            sw.Stop();

        }



        public void Logger_Timer(string message, Action action)

        {

            Logger_Timer(message, action, null);

        }



        public void Logger_Exception(string message, Action action, string fileName)

        {

            try

            {

                action();

            }

            catch (Exception ex)

            {

                InputLogger("代码段出现异常,信息为" + ex.Message, string.IsNullOrWhiteSpace(fileName)

                ? "Exception" + _defaultLoggerName

                : fileName);

            }

        }



        public void Logger_Exception(string message, Action action)

        {

            Logger_Exception(message, action, null);

        }



        public void Logger_Info(string message)

        {

            InputLogger(message, null);

        }



        public void Logger_Info(string message, string fileName)

        {

            InputLogger(message, string.IsNullOrWhiteSpace(fileName)

                 ? "Logger" + _defaultLoggerName

                 : fileName);

        }



        #endregion

    }
View Code

三 模版方式模式规定具体流程,抽象个性化方法

对于个性化的操作声明为抽象方法,在基类中实现统一的操作流程,在各个派生类中去实现个性化的模块,这正是模版方式模式的体现

四 策略模式以多种方式实现某个功能

对于文件持久化的方式有很多,而你可以分别去实现它,不知不觉中,我们正在使用策略模式来开发应用程序

普通持久化

我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
    /// <summary>

    /// 以普通的文字流的方式写日志

    /// </summary>

    internal class NormalLogger : LoggerBase

    {

        protected override void InputLogger(string message, string fileName)

        {

            string filePath = FileUrl + (fileName ?? "logger.log");

            string dir = filePath.Substring(0, filePath.LastIndexOf("\\"));

            if (!System.IO.Directory.Exists(dir))

            {

                System.IO.Directory.CreateDirectory(dir);

            }

            using (System.IO.StreamWriter srFile = new System.IO.StreamWriter(filePath, true))

            {

                srFile.WriteLine(message);

                srFile.Close();

                srFile.Dispose();

            }

        }

    }
View Code

log4net实现日志分级的持久化

我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
 /// <summary>

    ///  Function:以log4net组件的方式写日志

    ///  Remark:日志记录方法可以使用第三方组件,如log4net

    ///  Author:zhangzhanling

    ///  Blogs:www.cnblogs.com/lori

    ///  </summary>

    internal class Log4Logger : LoggerBase

    {

        /// <summary>

        /// log4net配置文件路径

        /// </summary>

        static string _logConfig = System.Web.HttpContext.Current.Server.MapPath("/log4net.config");



        static Log4Logger()

        {

            log4net.Config.XmlConfigurator.ConfigureAndWatch(new System.IO.FileInfo(_logConfig));

        }



        #region Prviate Methods

        /// <summary>

        /// 写日志方法

        /// </summary>

        /// <param name="message"></param>

        /// <param name="fileName"></param>

        protected override void InputLogger(string message, string fileName)

        {

            string filePath = FileUrl + fileName;

            var iLog = log4net.LogManager.GetLogger("Core.Logger");

            ChangeLog4netLogFileName(iLog, filePath, message);

        }



        private void ChangeLog4netLogFileName(log4net.ILog iLog, string filePath, string message)

        {

            log4net.Core.LogImpl logImpl = iLog as log4net.Core.LogImpl;

            if (logImpl != null)

            {

                var ac = ((log4net.Repository.Hierarchy.Logger)logImpl.Logger).Appenders;

                var rfa = ac[0] as log4net.Appender.RollingFileAppender;

                if (rfa != null)

                {

                    string dir = filePath.Substring(0, filePath.LastIndexOf("\\"));

                    if (!System.IO.Directory.Exists(dir))

                    {

                        System.IO.Directory.CreateDirectory(dir);

                    }

                    rfa.File = filePath;

                    // 更新Writer属性

                    rfa.Writer = new System.IO.StreamWriter(rfa.File, rfa.AppendToFile, rfa.Encoding);

                    rfa.Writer.WriteLine(message);

                    rfa.Writer.Close();

                    rfa.Writer.Dispose();

                    rfa.Close();



                }



            }

        }



        #endregion



    }
View Code

五 工厂模式动态生产对象,单例模式保持对象实例的唯一性

当我们以多种方式实现了对日志的持久化后,我们可以通过工厂模式动态的在这些持久化方式之间实现切换,对象实现单例之后,减少了内存开销,使对象的属性成为了全局性属性!

我心中的核心组件(可插拔的AOP)~第十五回 我的日志组件Logger.Core(策略,模版方法,工厂,单例等模式的使用)
    /// <summary>

    /// 日志生产类

    /// Singleton模式和策略模式和工厂模式

    /// </summary>

    public class LoggerFactory : ILogger

    {

        /// <summary>

        /// 对外不能创建类的实例

        /// </summary>

        private LoggerFactory()

        {



            string loggerType = System.Configuration.ConfigurationManager.AppSettings["LoggerType"] ?? "NormalLogger";

            switch (loggerType)

            {

                case "NormalLogger":

                    iLogger = new NormalLogger();

                    break;

                case "Log4Logger":

                    iLogger = new Log4Logger();

                    break;

                default:

                    throw new ArgumentException("日志方法不正确,目前只支持NormalLogger和Log4Logger");

            }

            //(ILogger)Assembly.Load("Logger.Core").CreateInstance("Logger.Core." + className.Trim());

        }



        #region Logger有多种实现时,需要使用Singleton模式



        private static object lockObj = new object();

        private static LoggerFactory instance = null;

        private ILogger iLogger = null;

        /// <summary>

        /// Get singleton instance of IoCFactory

        /// </summary>

        public static LoggerFactory Instance

        {

            get

            {

                if (instance == null)

                {

                    lock (lockObj)

                    {

                        if (instance == null)

                        {

                            instance = new LoggerFactory();

                        }

                    }

                }

                return instance;

            }

        }



        #endregion





        #region ILogger 成员



        public void Logger_Timer(string message, Action action, string fileName)

        {

            iLogger.Logger_Timer(message, action, fileName);

        }



        public void Logger_Timer(string message, Action action)

        {

            iLogger.Logger_Timer(message, action);

        }



        public void Logger_Exception(string message, Action action, string fileName)

        {

            iLogger.Logger_Exception(message, action, fileName);

        }



        public void Logger_Exception(string message, Action action)

        {

            iLogger.Logger_Exception(message, action);

        }



        public void Logger_Info(string message)

        {

            iLogger.Logger_Info(message);

        }



        public void Logger_Info(string message, string fileName)

        {

            iLogger.Logger_Info(message, fileName);

        }



        #endregion

    }
View Code

最后有一句话送给大家:坚持,其实就是一种胜利!

回到目录

你可能感兴趣的:(Logger)