实用单例和依赖注入问题

Epa*_*aga 15 singleton dependency-injection

假设我有一个名为PermissionManager的类,它应该只对我的系统存在一次,并且基本上实现了管理应用程序中各种操作的各种权限的功能.现在我的应用程序中有一些类需要能够在其中一种方法中检查某个权限.此类的构造函数目前是公共的,即由API用户使用.

直到几周前,我本来只是让我的类在某处调用以下伪代码:

     PermissionManager.getInstance().isReadPermissionEnabled(this)
Run Code Online (Sandbox Code Playgroud)

但是因为我注意到每个人都讨厌单身人士+这种耦合,我想知道什么是更好的解决方案,因为我对单身人士的论证似乎有意义(不可测试,高耦合等).

那么我是否应该要求API用户在类的构造函数中传入PermissionManager实例?即使我只想为我的应用程序存在一个PermissionManager实例?

或者我是否认为这一切都错了,应该有一个非公共构造函数和一个工厂,它在我的PermissionManager实例中传递?


附加信息请注意,当我说"依赖注入"时,我在谈论DI 模式 ......我没有使用像Guice或Spring这样的任何DI框架.(...然而)

Edd*_*eyo 3

如果您使用的是依赖项注入框架,那么处理此问题的常用方法是在构造函数中传入 PermissionsManager 对象,或者拥有框架为您设置的 PermissionsManager 类型的属性。

如果这不可行,那么让用户通过工厂获取此类的实例是一个不错的选择。在这种情况下,工厂在创建类时将 PermissionManager 传递给构造函数。在应用程序启动时,您将首先创建单个 PermissionManager,然后创建工厂并传入 PermissionManager。

您是对的,类的客户端通常很难知道在哪里找到正确的 PermissionManager 实例并将其传入(甚至关心您的类使用 PermissionManager 的事实)。

我见过的一种折衷解决方案是为您的类提供 PermissionManager 类型的属性。如果该属性已设置(例如,在单元测试中),则使用该实例,否则使用单例。就像是:

PermissionManager mManager = null;
public PermissionManager Permissions
{
  if (mManager == null)
  {
    return mManager;
  }
  return PermissionManager.getInstance();
}
Run Code Online (Sandbox Code Playgroud)

当然,严格来说,您的 PermissionManager 应该实现某种 IPermissionManager 接口,这就是您的其他类应该引用的接口,以便在测试期间可以更轻松地替换虚拟实现。

  • 通过接口注入的这一点很重要。在测试中模拟 PermissionManager 对象的能力使 DI 成为更可测试代码的强大方法。 (2认同)