几乎在每个项目中,我创建了几个实现Singleton模式的类。例如,数据管理器 - 如果有一些文件系统的工作,数据加载器 - 如果一个应用程序连接到互联网,不同的资源管理器等等。有时候有多达5-7个这样的类,我开始觉得我在做有问题。使用Singleton模式太糟糕了吗?项目中的单身人士太多 - 这是一种不好的做法吗?
回答
单身并不一定问题 - 有一个单一的对象,它是在其领域的专家是非常有用的 - 但明确地编码单岬到对象几乎总是一个坏主意(并且经常做得不好太)。事实证明,将应用程序的配置(包括对哪些类具有单例实例化的决定)保留到专门用于此的单独层(如Spring for Java)上会更好。像这样,管理层可以管理什么是单身人士,什么是特定背景下的单身人士(例如,在会话范围内)以及总是需要重新制造的单身人士。这使您可以专注于编写业务逻辑。
有关单例可能会出现问题的原因以及管理/配置应该是单例的原因的示例,请考虑管理与数据库的连接的类。你可能会说一个单例的经典案例。你也可以,直到你发现你的应用程序已经发展到必须将连接集成到两个数据库(它发生了!),然后你必须解决整个混乱。如果你已经保存了你的代码不知道它是否处理单例,你很有可能通过重新配置来处理它;一些课程将连接到一个数据库,另一些则连接到另一个数据库,但他们只会用最小的麻烦继续进行。 (任何事情都需要......嗯,这就是为什么我说“很好的机会”。)
当你为你的代码编写测试时,为什么Singletons可能会出现问题的另一个例子。 (你会写测试,是吗?)显式单例测试非常困难,因为它们很难配置并且很难分离。测试之间不能正确地撕下它们,因为这意味着它们中有很多。如果您的应用程序仅通过配置使用单身人士,测试配置可以轻松更改,并且您可以更轻松地完成测试。
关于这个话题有很多讨论。对于某些人,Singleton被认为是anti-pattern。它可以是非常有用的,但它似乎要比看起来更加棘手。在某些情况下,它的使用是合理的,例如为整个应用程序提供一个共同数据的唯一入口点 - 其中存在棘手的部分,它是伪装的全局状态,当且仅当数据是不可变的时候才是安全的。
正如旁注所示,Java企业版的最新版本JEE6现在包含用于Singleton模式的support作为EJB组件。但想一想,花了六个修订标准终于完成!
由于TDD取代了自己的地位,程序员学会了测试单例是一种痛苦,并开始避免它。通过注入所需的类/资源(例如连接管理器,资源管理器等)也可以实现同样的效果。以这种方式,在测试环境中,这些类可以简单地被模拟,注入并覆盖测试。
另一方面,在某些情况下,只有使用singleton似乎是正确的方式 - 确保只有一个实例存在。即它对于连接池非常有用,它保证当前只有一个实例存在,并且不会有泄漏。 (注意:并不是所有的单例模式的实现都可以真正提供这个。在Java中,正确的方法是使用枚举 - 因为语言本身确保了它的唯一性。)
总之,我的回答是肯定的,使用太多的单例是不好的。考虑使用DI原理。
有趣的文章,单身人士是反模式,虽然我不完全同意。我从来没有使用单例作为独立的解决方案,我一直将它与factory模式结合在一起,我认为它可以减少状态和封装的争论。
单例/工厂解决方案的一个很好的例子是数据库类。您可能有多个数据库,每个数据库都需要自己的连接,但您不希望每个调用都实例化并创建新的连接。您想要回收共享连接以避免“太多连接”地雷。
东西沿着线:
/**
* Database manager for handling database related stuff
* Does use Zend_Db and Zend_Config
*/
class Database_Manager
{
protected static $dbos = array(); // Protected scope enforces encapsulation
public static function getDbo($name)
{
// Init
$hash = md5($name);
// Attempt to use singleton
if (array_key_exists($hash, self::$dbos)) {
return self::$dbos[$hash];
}
// Your db connection settings are set here either via
// switch/case based on name, or loaded from a config file (yaml, xml, etc)
$dbConnectionParams = array('your', 'connection', 'settings');
$config = new Zend_Config($dbConnectionParams);
$dbo = Zend_Db::factory($config->database);
// Adding to singleton so can be referenced in future calls
self::$dbos[$hash] = $dbo;
return $dbo;
}
在这个例子中,工厂确保封装,而单回收已实例的数据库对象。
在一天结束时,取决于您和您想要支持的道路。
- 1. 单身人士知道是不好的做法,角度是基于单身人士。角度不好?
- 2. 我的单身人士模板真的是单身人士吗?
- 3. 名单<Class>单身人士,这是甚至良好的做法?
- 4. servlet是单身人士吗?
- 5. 在这种情况下,单身人士GUI会不错吗?
- 6. 单身人士在GWT项目
- 7. 这真的是一个单身人士吗?
- 8. 单身人士在MVP GWT项目
- 9. 单身人士目标C
- 10. 这是如何推动单身人士?
- 11. JavaScript:window.spam是一种很好的做法吗?
- 12. instanceof是一种好的做法吗?
- 13. JDBC连接池是单身人士吗?
- 14. 这种布尔方法是不好的做法吗?
- 15. Hibernate中的身份生成器是单身人士吗?
- 16. 使用单身人士和调解人为了沟通项目
- 17. 如果父对象不是单身人士,那么孩子是单身人士?
- 18. Python中的单身人士
- 19. ASP.NET中的单身人士
- 20. iOS中的单身人士
- 21. 这是不好的做法吗? C++
- 22. 这是不好的做法吗?
- 23. 在xCode项目中有多个* .xcodeproj文件是否是一种好的做法?
- 24. 单元测试私有方法是一种好的做法吗?
- 25. 检查字典中是否存在项目,这是不好的做法吗?
- 26. 在这种情况下使用uint64_t是不好的做法吗?
- 27. 这个单身人士的问题(不是课程)
- 28. 由Singleton包装的单身人士或非单身人士
- 29. 组成vs多个单身人士
- 30. 这是一个温莎单身人士线程安全的依赖吗?
代码中定义的单例总是错误的。单身人士在高层次文件中定义为“只能有一个此类的实例”是可以接受的。 – Raynos