代码之家  ›  专栏  ›  技术社区  ›  Epaga Alex Reynolds

实际单例与依赖注入问题

  •  15
  • Epaga Alex Reynolds  · 技术社区  · 16 年前

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

    直到几周前,我还只是让我的班级在某个地方调用以下伪代码:

         PermissionManager.getInstance().isReadPermissionEnabled(this)
    

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

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

    或者,我是不是犯了所有错误,应该在某个地方拥有一个非公共的构造函数和一个通过PermissionManager实例的工厂?


    附加信息 请注意,当我说“依赖注入”时,我指的是DI Pattern …我没有使用任何像guice或spring这样的DI框架。(……)

    5 回复  |  直到 16 年前
        1
  •  3
  •   community wiki Eddie Deyo    16 年前

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

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

    对于类的客户机来说,知道在哪里找到正确的PermissionManager实例并将其传入(甚至关心类使用PermissionManager这一事实)通常是不方便的,这是正确的。

    我看到的一个折衷的解决方案是为类提供PermissionManager类型的属性。如果已经设置了属性(例如,在单元测试中),则使用该实例,否则使用单例。类似:

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

    当然,严格来说,PermissionManager应该实现某种类型的IPermissionManager接口,并且 那是 您的其他类应该引用什么,以便在测试期间更容易替换虚拟实现。

        2
  •  2
  •   Mendelt    16 年前

    实际上,您可以从注入PermissionManager开始。这将使类更具可测试性。

    如果这会给该类的用户带来问题,您可以让他们使用工厂方法或抽象工厂。或者,您可以添加一个无参数的构造函数,让它们调用它来注入PermissionManager,而您的测试使用另一个构造函数来模拟PermissionManager。

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

        3
  •  2
  •   Mike Furtak    16 年前

    如果您订阅了依赖项注入方式,那么无论什么类需要您的 PermissionManager 应该将其作为对象实例注入。控制其实例化(以强制实现单例性质)的机制在更高的级别上工作。如果您使用一个类似guice的依赖注入框架,它可以完成强制工作。如果您是手工进行对象连接,依赖注入倾向于将代码分组,使其远离业务逻辑进行实例化(新的操作员工作)。

    不管怎样,经典的“capital-s”单例通常被视为依赖注入环境中的反模式。

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

        4
  •  1
  •   user7375    16 年前

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

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

        5
  •  0
  •   Trap    16 年前

    单例模式本身并不坏,它之所以难看是因为它通常被使用,因为它要求只需要某个类的一个实例,我认为这是一个很大的错误。

    在本例中,我将PermissionManager设置为静态类,除非出于任何原因需要它是不可恢复的类型。