2008-10-29 60 views
15

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

直到几个星期前,我会简单地过我的课叫下面的伪代码的地方:

 PermissionManager.getInstance().isReadPermissionEnabled(this) 

但因为我已经注意到这里的每个人恨的单身+这种耦合的,我是想知道更好的解决方案是什么,因为我读过的关于单身人士的论点似乎有意义(不可测试,高度耦合等)。

所以我应该实际上要求API用户在类的构造函数中传递PermissionManager实例吗?即使我只想为我的应用程序存在单个PermissionManager实例?

或者我正在做的这一切都错了,应该有一个非公开的构造函数和一个工厂的地方,在PermissionManager的实例中传递给我?


其他信息需要注意的是,当我说“依赖注入”,我说的是DI Pattern ...我不使用像吉斯或Spring任何DI框架。 (...)

回答

3

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

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

对于一个类的客户端来说,通常很难知道哪里可以找到正确的PermissionManager实例并将其传入(或者甚至关心您的类使用PermissionManager)。

我看到的一个折中解决方案是给你的类一个PermissionManager类型的属性。如果属性已经设置(比如在单元测试中),那么使用该实例,否则使用单例。喜欢的东西:

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

当然,严格来说,你应该PermissionManager实现某种IPermissionManager接口,并你的其他类应该参考什么使一个虚拟实现,可以在测试过程中更容易被取代。

+1

关于通过接口注入的观点非常重要。在测试中模拟PermissionManager对象的能力使得DI成为更多可测试代码的强大方法。 – 2008-10-29 14:53:40

0

单身模式本身并不坏,是什么让它变丑是它常用的方式,因为它只需要某个类的单个实例,我认为它是一个大错。

在这种情况下,我会让PermissionManager成为一个静态类,除非因为任何原因你需要它是一个实例类型。

2

确实可以通过注入PermissionManager来启动。这会让你的课更具可测性。

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

解耦你的类更多使你的类更灵活,但它也可以使它们更难使用。这取决于你需要的情况。如果你只有一个PermissionManager,并且没有问题测试使用它的类,那么没有理由使用DI。如果你希望人们能够添加他们自己的PermissionManager实现,那么DI就是要走的路。

2

如果您正在订阅依赖注入的方式,无论您需要什么类PermissionManager都应该将其注入为对象实例。控制其实例化的机制(强制单例性)在更高层次上工作。如果你使用像Guice这样的依赖注入框架,它可以执行强制工作。如果您正在手动进行对象连接,则依赖注入有利于将实例化(新操作员工作)的代码分组到远离业务逻辑的位置。不过,无论哪种方式,经典的“大写S”单例通常被视为依赖注入环境中的反模式。

这些职位已经有见地的,我过去:

1

所以应我实际上需要API用户在PermissionManager实例传递在构造函数中的班级?即使我只想为我的应用程序存在单个PermissionManager实例?

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