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

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

     PermissionManager.getInstance().isReadPermissionEnabled(this)

但由于我注意到这里的每个人都讨厌单例+这种耦合,所以我想知道更好的解决方案是什么,因为我读过的反对单例的论点似乎是有道理的(不可测试,高耦合等)。

那么我实际上应该要求 API 用户在类的构造函数中传入 PermissionManager 实例吗?即使我只希望我的应用程序存在一个 PermissionManager 实例?

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


附加信息 请注意,当我说“依赖注入”时,我指的是 DI 图案...我没有使用任何像 Guice 或 Spring 这样的 DI 框架。(...然而)

有帮助吗?

解决方案

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

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

对于类的客户端来说,知道在哪里找到正确的PermissionManager实例并将其传入(或者甚至关心您的类使用PermissionManager这一事实),这是正确的,这是正确的。

我见过的一个妥协解决方案是为您的类提供PermissionManager类型的属性。如果已设置属性(例如,在单元测试中),则使用该实例,否则使用单例。类似的东西:

PermissionManager mManager = null;
public PermissionManager Permissions
{
  if (mManager == null)
  {
    return mManager;
  }
  return PermissionManager.getInstance();
}

当然,严格来说,你的PermissionManager应该实现某种IPermissionManager接口,那是你的其他类应该引用的东西,这样在测试过程中可以更容易地替换虚拟实现。

其他提示

您确实可以从注入PermissionManager开始。这将使您的课程更加可测试。

如果这会导致该类用户出现问题,您可以让他们使用工厂方法或抽象工厂。或者,您可以添加一个无参数构造函数,供他们调用以注入PermissionManager,同时您的测试使用另一个可用于模拟PermissionManager的构造函数。

将您的课程更加分离会使您的课程更加灵活,但也会使课程难以使用。这取决于您需要的情况。如果您只有一个PermissionManager并且测试使用它的类没有问题,那么就没有理由使用DI。如果您希望人们能够添加自己的PermissionManager实现,那么DI就是您的选择。

如果您订阅依赖注入方式做事,任何类都需要您的 PermissionManager 应该将其作为对象实例注入。控制其实例化(以强制单例性质)的机制在更高级别上工作。如果您使用像 Guice 这样的依赖注入框架,它可以完成强制执行工作。如果您手动进行对象连接,依赖注入有利于对远离业务逻辑进行实例化(新操作符工作)的代码进行分组。

但无论如何,经典的“大写-S”单例通常被视为依赖注入上下文中的反模式。

这些帖子过去对我来说很有洞察力:

  

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

是的,这就是你需要做的。依赖关系是单个/每个请求/每个线程还是工厂方法是容器和配置的责任。在.net世界中,我们理想地依赖于IPermissionsManager接口以进一步减少耦合,我认为这也是Java中的最佳实践。

单身模式本身并不坏,它的丑陋之处在于它常用的方式,因为只需要某个类的单个实例,我认为这是一个很大的错误。

在这种情况下,我会将PermissionManager设为静态类,除非出于任何原因需要它是一个可实现的类型。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top