6

情况是这样的:我有一堂课做得太多了。它主要用于访问配置信息,但它也有数据库连接。它是作为单例实现的,因此这也使单元测试变得困难,因为大多数代码都与它紧密耦合。这更成问题,因为它创建了一个导入时依赖项(我们在 Python 中这样做),这意味着某些模块必须按特定顺序导入。理想情况下,我想将其分为两个类并使其成为非单例。

幸运的是,我的雇主已经意识到这种测试是好的,并且如果它使代码更具可测试性,他愿意允许我进行这样的更改。但是,我怀疑他们是否愿意让我在上面花费太多时间。我宁愿逐步解决这个问题,也不愿过于激进。

所以,我在这里看到三个选择:

  1. 将配置对象分解为(单例)配置对象和(非单例)数据库对象。这至少可以让我将数据库作为导入时依赖项删除。
  2. 使配置对象成为非单例并将其传递给需要它的对象。我觉得这更好地满足了我们的短期需求,但我认为这需要更多的时间。
  3. 做一些我没有想到的你在回答中建议的事情。:-)

那我该怎么办?

4

4 回答 4

5

不看你的代码很难知道,但为什么不照你说的做——逐步做呢?首先执行步骤 1,拆分数据库。

如果这很快,然后返回,你现在只有 1 个更小的对象来停止成为单例而不是 2。所以第 2 步应该更快。或者在这个阶段,您可能会看到其他一些可以从单例中重构出来的代码。

希望您可以逐步减少单例中的内容,直到它消失,而无需在任何一步中支付大量时间税。

例如,如果配置的各个部分是独立的,那么也许可以一次将配置的一个部分设为单例。所以也许GUI配置在文件配置重构时留下了单例,或者类似的东西?

于 2009-07-03T15:41:19.237 回答
5

我认为您有望分成两个班级。您可能需要考虑使用工厂来根据需要创建数据库上下文/连接。这样,您可以将连接视为根据需要创建/处置的工作实体单元,而不是在对象的生命周期内保持单个连接。不过,YMMV。

至于配置,这是我发现单例可能是正确选择的一种情况。我不一定会因为难以进行单元测试而抛弃它。不过,您可能需要考虑构建它来实现接口。然后,您可以在测试期间使用依赖注入来提供接口的模拟实例。如果注入的值为空,您的生产代码将被构建为使用单例实例或注入单例实例。或者,您可以构造该类以允许通过私有方法重新初始化,并在您的设置/拆卸测试方法中调用它,以确保它具有适合您的测试的配置。我更喜欢前者而不是后者实现,尽管当我无法直接控制界面时我也使用过它。

逐步进行更改绝对是要走的路。如果可能的话,用测试包装当前的功能,并确保这些测试在你的修改之后仍然通过(当然,不是那些直接处理你的修改的测试)是确保你没有破坏其他代码的好方法.

于 2009-07-03T15:48:43.747 回答
2

选项 1 是我在所有应用程序中所做的:配置对象单例和按需创建或注入的数据库对象。

将配置对象作为单例对我来说一直是完美的选择。只有一个配置文件,我总是想在应用程序启动时阅读它。

于 2009-07-03T15:43:00.530 回答
2

请原谅我不懂任何 Python,所以我希望任何伪代码都有意义......

我首先将对象分成两部分,以便您的单例的职责更小,然后我将采用剩余的配置单例并将其更改为普通类(就好像您要执行第二个建议一样)。

一旦我做到了这一点,我将创建一个新的包装单例,它公开配置类的方法:

class ConfigurationWrapper : IConfigurationClass 
{
    public static property ConfigurationWrapper Instance;

    public property IConfigurationClass InnerClass;

    public method GetDefaultWindowWidth()
    {
        return InnerClass.GetDefaultWindowWidth();
    }

    etc...
}

现在应用程序做的第一件事就是将 ConfigurationClass 的一个实例注入到包装器中。

ConfigurationClass config = new ConfigurationClass()
ConfigurationWrapper.Instance.InnerClass = config;

最后,您可以将当前依赖单例的类移动到包装单例(这应该是一个快速查找和替换)。现在您可以一次一个地转换类以通过其构造函数获取配置对象以完成第 2 阶段。任何您没有时间做的事情都可以使用包装器单例。一旦你将它们全部移动,你就可以摆脱包装。

另一方面,您可以忽略对用法的重构,只需将模拟的配置类注入到单例包装器中进行测试——本质上是穷人的依赖注入。

于 2009-07-03T15:51:04.783 回答