如何重构单例class,避免重蹈覆辙
How to refactor a singleton class and avoid doing the same mistakes again
我在 WPF 中启动了一个小应用程序并使用单例 class 来处理所有应用程序逻辑。另外,我有一些 ObservableCollections 绑定到视图上的 DataGrids。
问题:本来应该是一个小程序的功能开始增加,代码现在太难维护、重用并且代码耦合度很高。
因此我开始将代码移至其他 classes。例如,我有一个只处理文件读数的 class。我已将此 class 设为静态,因为我只 运行 这些方法一次(当我需要将数据导入数据库时),当它们完成后,我不再需要这些对象,只是忘记了他们存在。
现在我正在考虑对其他方法做同样的事情,比如从数据库中检索数据的方法。
我怀疑这是否是解决问题的正确方法?恐怕使用静态 classes 会像单例的乘法。
静态 classes 被一些人认为是邪恶的,但这只是一种观点。当我有这些问题时,我看一下.NET-framework:里面是怎么解决的?
有时可以将单例重构为静态 class。这取决于实际情况。如果你的单例是继承(阅读:必须继承)其他classes或接口的类型,它不能转换为静态class,因为静态class不能继承任何东西。
如果创建静态class,尽量遵守以下规则:(.NET框架也遵守这些规则):
- 所有静态成员必须是线程安全的。
就是这样! :)
这条规则听起来很简单,但蕴含着很多:
- 所有静态成员彼此独立工作。所以一个调用永远不会影响另一个调用的结果。
- 不允许静态 class 保持(静态)状态。
- 如果 class 有静态字段,请确保它们是只读的或常量的。确保这些字段的内容永远不会改变。
当然也有一些小例外。例如:静态 class 可以维护一个用于缓存结果的内部字典。修改这个缓存必须是线程安全的。因为它是内部的东西,所以对于外部世界,静态 class 仍然遵守上述规则。
所以...简而言之:如果您的单例不是线程安全的(保持状态等),请不要将其转换为静态 class。
* 编辑 *
使用单例通常意味着您有一个静态 属性 包含一个特定类型的实例。由于这是一个静态 属性 它也必须遵守上述规则,这意味着该实例必须是线程安全的。
如果您的(单例)实例不是线程安全的,请重新设计您的应用程序,使其不使用此单例或静态 class。让所有代码在需要时创建此 class 的新实例。
我在 WPF 中启动了一个小应用程序并使用单例 class 来处理所有应用程序逻辑。另外,我有一些 ObservableCollections 绑定到视图上的 DataGrids。
问题:本来应该是一个小程序的功能开始增加,代码现在太难维护、重用并且代码耦合度很高。
因此我开始将代码移至其他 classes。例如,我有一个只处理文件读数的 class。我已将此 class 设为静态,因为我只 运行 这些方法一次(当我需要将数据导入数据库时),当它们完成后,我不再需要这些对象,只是忘记了他们存在。
现在我正在考虑对其他方法做同样的事情,比如从数据库中检索数据的方法。
我怀疑这是否是解决问题的正确方法?恐怕使用静态 classes 会像单例的乘法。
静态 classes 被一些人认为是邪恶的,但这只是一种观点。当我有这些问题时,我看一下.NET-framework:里面是怎么解决的?
有时可以将单例重构为静态 class。这取决于实际情况。如果你的单例是继承(阅读:必须继承)其他classes或接口的类型,它不能转换为静态class,因为静态class不能继承任何东西。
如果创建静态class,尽量遵守以下规则:(.NET框架也遵守这些规则):
- 所有静态成员必须是线程安全的。
就是这样! :)
这条规则听起来很简单,但蕴含着很多:
- 所有静态成员彼此独立工作。所以一个调用永远不会影响另一个调用的结果。
- 不允许静态 class 保持(静态)状态。
- 如果 class 有静态字段,请确保它们是只读的或常量的。确保这些字段的内容永远不会改变。
当然也有一些小例外。例如:静态 class 可以维护一个用于缓存结果的内部字典。修改这个缓存必须是线程安全的。因为它是内部的东西,所以对于外部世界,静态 class 仍然遵守上述规则。
所以...简而言之:如果您的单例不是线程安全的(保持状态等),请不要将其转换为静态 class。
* 编辑 *
使用单例通常意味着您有一个静态 属性 包含一个特定类型的实例。由于这是一个静态 属性 它也必须遵守上述规则,这意味着该实例必须是线程安全的。
如果您的(单例)实例不是线程安全的,请重新设计您的应用程序,使其不使用此单例或静态 class。让所有代码在需要时创建此 class 的新实例。