【问题标题】:better way to write wrapper class to get loose coupling编写包装类以获得松耦合的更好方法
【发布时间】:2012-04-24 19:25:29
【问题描述】:
class LogUtil<T> : ILogUtility
{
    log4net.ILog log;

    public LogUtil()
    {
        log = log4net.LogManager.GetLogger(typeof(T).FullName);
    }

    public void Log(LogType logtype, string message)
    {
        Console.WriteLine("logging coming from class {0} - message {1} " , typeof(T).FullName, message);
    }
}

public class Logger
{
    ILogUtility _logutility;

    public Logger(ILogUtility logutility)
    {
        _logutility = logutility;
    }


    public void Log(LogType logtype, string message)
    {
        _logutility.Log(logtype, message);
    }


}

我需要具有灵活的功能,并且能够在将来删除 LogUtil 类并使用其他东西。

所以我编写 LoggerUtility 包装类如下:

class LoggerUtility<T>
{
    public Logger logger
    {
        get
        {

            LogUtil<T> logutil = new LogUtil<T>();

            Logger log = new Logger(logutil);

            return log;
        }
    }
}

我的客户端代码如下:

public class TestCode
{
    public void test()
    {

        new LoggerUtility<TestCode>().logger.Log(LogType.Info, "hello world");

    }

}

我正在编写可能不干净的 Logger 属性。

正如您所见,以下行看起来并不干净。

new LoggerUtility<TestCode>().logger.Log(LogType.Info, "hello world");

有没有更好的方法来编写客户端代码?我想与 LogUtil 松耦合,而不是直接在我的客户端代码中使用它。

请告诉我。

谢谢

【问题讨论】:

  • 为什么不针对LogUtil&lt;T&gt;实现的ILogUtil接口编写代码?
  • 让记录器的客户端依赖ILogUtil而不是LogUtil&lt;T&gt;,即ILogUtil logger = GetLogger();而不是LogUtil&lt;T&gt; = GetLogger();。然后,您可以根据需要更改实现。或者,您可以直接依赖 log4net(或其ILog 接口),因为您不太可能需要更改记录器实现。

标签: c# generics log4net


【解决方案1】:

cmets 中提供的答案是正确的(客户端应该依赖接口ILogUtil,而不是直接依赖具体的实现)。还有无数其他问题:

  • 每次记录消息时,您都会实例化 LoggerUtility&lt;T&gt; Logger 类的新实例。也许这里的东西应该是静态的?额外的层(LoggerUtility)有什么意义?

  • 您对泛型 (LoggerUtility&lt;T&gt;) 的使用并不完全有意义,因为您不必只输入 T,而且您没有使用该信息。

实际上,编写自己的日志外观是其他人已经花费的努力 - 只需使用现有的实现即可。我可以为log4netNLog 担保,但如果您希望有灵活性,请在Castle.Services.Logging 中选择适当的外观,它具有前面提到的实现的适配器(您可以编写自己的!)。

更多信息在这里:Is there a logging facade for the .NET world?

【讨论】:

    【解决方案2】:

    取决于您希望日志包装器的行为有多复杂?

    日志记录有多个级别,信息和异常是常态。

    关于使用接口的答案是 100% 正确的,但也有 DRY(不要重复自己)的原则。

    如果您发现您的代码看起来非常重复,就像我的一样,那么也许除了使用注入和接口等标准之外,还可以围绕错误处理实现一个通用包装器。

    泛型允许您分离解决方案的逻辑并允许重用,接口允许您将日志记录的概念与物理实现分离。

      public static output ExecuteBlockwithLogging<output, input, config>(ExeBlock<output, input, config> exeBlock, input InputForExeBlock, ILoggingBlock logger)
        {
    
            exeBlock.Execute(InputForExeBlock);
    
            if ((exeBlock.logEntries != null) && (exeBlock.logEntries.Length > 0))
            {
                logger.Execute(exeBlock.logEntries);
            }
    
    
            if ((exeBlock.exceptions != null) && (exeBlock.exceptions.Length > 0))
            {
                foreach (var e in exeBlock.exceptions)
                {
    
                    var dictionaryData = new Dictionary<string, string>();
                    if (e.Data.Count > 0)
                    {
                        foreach (DictionaryEntry d in e.Data)
                        {
                            dictionaryData.Add(d.Key.ToString(), d.Value.ToString());
                        }
                    }
    
                    var messages = e.FromHierarchy(ex => ex.InnerException).Select(ex => ex.Message);
    
    
                    LoggingEntry LE = new LoggingEntry
                    {
                        description = e.Message,
                        exceptionMessage = String.Join(Environment.NewLine, messages),
                        source = exeBlock.GetType().Name,
                        data = dictionaryData
                    };
    
                    logger.Execute(new LoggingEntry[] { LE });
                }
                return default(output);
            }
    
            return exeBlock.Result;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-09
      • 1970-01-01
      • 2020-02-17
      • 2023-03-10
      • 1970-01-01
      • 2013-01-16
      • 2018-11-19
      相关资源
      最近更新 更多