0

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

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

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

4

5 回答 5

6

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

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

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

为有些随意的沉思道歉-我还没有喝第一杯咖啡。希望它是有帮助的。

于 2008-10-09T06:34:30.353 回答
5

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

这样,您将获得两全其美。

于 2008-10-09T06:11:33.003 回答
0

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

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

于 2008-10-12T08:50:27.507 回答
0

添加到Trav所说的......

除了 Log 的 Singleton 实现之外,您还可以将它包装在静态类周围。这样您就不需要更改已经使用静态 Log 类的位置。并且为您的单元测试交换模拟日志框架将非常容易。我将在 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);
    }
}
于 2008-10-12T17:41:50.617 回答
-1

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

于 2008-10-09T06:24:28.190 回答