【问题标题】:Initializing static objects - Code design question初始化静态对象 - 代码设计问题
【发布时间】:2008-10-09 06:06:50
【问题描述】:

在我的 web 应用程序(C#,.Net 3.5)中,由一个 core 类库(包含业务逻辑、数据层和几个实用程序类)、一个 Windows 服务项目、一个webservice 项目和网站项目,我在所有其他项目使用的 core 库中有几个静态类。这些类(例如 Log 类)需要一些初始化(它们有一个 Initialize 方法)才能设置它们以供使用。例如,Log 类的Initialize 方法有一个目录路径参数,它告诉Log,将日志文件保存到哪里。或者,我正在考虑从静态构造函数的配置文件中加载 Log 类的“设置”。缺点是,我需要在生产代码中进行不同的单元测试设置。

有没有更好的设计方法?这种方法的缺点是,静态类的所有使用者都将尝试调用 Initialize。这不是一个真正的问题,因为一旦初始化,该方法将立即返回,而不是再次执行 Initialize 代码,但设计对我来说似乎有点奇怪。

我希望我的英语足以解释我所追求的。如果问题不够清楚,请不要犹豫。

【问题讨论】:

    标签: c# design-patterns architecture static


    【解决方案1】:

    对于需要初始化的东西,我会尽量避免使用静态类。使您的 Log 类成为普通类,并且可能有一个单独的工厂类来创建实例或单个实例。您可能希望使用依赖注入来避免任何静态,尽管这对于非常普遍的日志记录之类的东西可能会很痛苦。

    特别是对于日志记录,log4net 和 log4j (顺便说一句,你有什么理由自己滚动?)都使用根据名称(通常基于使用它的类型的名称)向某些工厂类询问日志实例的习惯用法)。这通常存储在每个需要执行日志记录的类中的静态变量中。如果返回的日志对象仍然会受到之后的日志子系统初始化的影响,那么您最终不会遇到顺序问题,即 DI 容器必须在日志客户端初始化之前初始化日志框架等。

    使用单独的日志记录对象而不是静态类可以提高可测试性 - 您可以在测试期间将日志记录对象替换为记录日志的对象,以确保捕获(例如)审计信息。静态已知的日志记录对象的一个​​缺点是这会降低并行运行测试的可能性。

    对于有些随意的沉思表示歉意 - 我还没有喝过第一杯咖啡。不过希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      如果初始化成本很高,我建议使用单例(如果您不熟悉设计模式,请使用谷歌单例设计模式)。作为实例构建的一部分,您随后会读入一个配置文件,该文件可以特定于环境。

      这样你就可以两全其美了。

      【讨论】:

        【解决方案3】:

        我认为您在问题中给出的任何一种解决方案都可以。从您的 Main 方法调用 Initialize 一次(或将其放在从 Main 调用的某个单独的 SetupApplicationInfrastructure 方法中)。或者,在构造函数中加载一次设置。

        我认为您不必担心每次访问实例时都要检查是否需要初始化。这样做还不错。

        【讨论】:

          【解决方案4】:

          补充 Trav 所说的......

          除了 Log 的 Singleton 实现之外,您还可以将它包装在静态类周围。这样您就不需要更改已经使用静态 Log 类的位置。并且为您的单元测试交换模拟 Logging 框架将非常容易。我将在 Java 中给出一个示例 - 假设您有如下所示的内容:

          public class Log
          {
              public static void debug(Object o, String message)
              {
                  System.out.println(o + " [DBUG] " + message);
              }
          
              public static void info(Object o, String message)
              {
                  System.out.println(o + " [INFO] " + message);
              }
          }
          

          你可以像下面这样重构它:

          public interface ILoggeer
          {
              void debug(Object o, String message);
              void info(Object o, String message);
          }
          
          public class Log
          {
              private static ILogger log = new ConsoleLogger();
          
              public static setLogger(ILogger impl)
              {
                  log = impl;
              }
          
              public static void debug(Object o, String message)
              {
                  log.debug(o, message);
              }
          
              public static void info(Object o, String message)
              {
                  log.info(o, message);
              }
          }
          
          public class ConsoleLogger implements ILogger
          {
              public void debug(Object o, String message)
              {
                  System.out.println(o + " [DBUG] " + message);
              }
          
              public void info(Object o, String message)
              {
                  System.out.println(o + " [INFO] " + message);
              }
          }
          

          【讨论】:

            【解决方案5】:

            我认为您必须在这里提出难题。这些东西需要是静态的吗?静态对象,无论是否是单例形式,都很难使用。如果你真的需要静态,也许像monostate pattern 这样的东西可以帮助你。它就像一个多态静态类。通常,所有成员变量都是静态的,而构造函数则不是。也许有了这个,你可以继承这个类,并根据你的需要做一些覆盖。只是一个想法。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2012-02-23
              • 1970-01-01
              • 2011-11-11
              • 1970-01-01
              • 1970-01-01
              • 2023-02-15
              • 2013-03-21
              相关资源
              最近更新 更多