单身人士真的不好吗?
可能重复:
单身人士有什么不好?
可以理解的是,许多devise模式在某些情况下可能会被滥用,像妈妈一样总是这样说:“ 太多的好东西并不总是好的! ”
我注意到,这些日子里,我很多都在使用单身人士,我担心自己会滥用devise模式,并且越来越深入到一种坏习惯的习惯中去。
我们正在开发一个Flex应用程序,在用户使用这个应用程序的时候,这个应用程序有一个相当大的分层数据结构。 用户可以根据需要加载,保存,更改和刷新数据。
这个数据通过一个Singleton类来集中,它聚合了一些ArrayCollections,Arrays,value对象和一些其他通过getter和setter公开的本地成员variables。
为了从应用程序中的任何位置获取对我们数据的引用,我们确实熟悉了所有的Model.getInstance()方法types的东西。 这确保了我们始终掌握相同的数据副本,因为当我们devise时,我们说在应用程序生命周期中只允许存在一次实例。
从这个中央数据存储库,我们可以很容易地例如调度属性更改的事件,并可以有多个引用中央数据的UI组件,更新其显示以反映已发生的数据更改。
到目前为止,这种方法是有效的,并certificate对我们的情况非常实际。
然而,我发现在创build新课程时我有点过激。 类似Singleton这样的问题,还是应该用其他方式来pipe理,比如可能使用工厂,有时会变得有些困难,有些不确定。
我在哪里画单行? 是否有一个很好的指导方针来决定何时使用单身人士,以及何时离开他们。
另外,任何人都可以推荐一本关于devise模式的好书吗?
要记住的关键是devise模式只是帮助你理解抽象概念的工具。 一旦你有了这样的理解,将自己特别限制在一本书的“配方”中是毫无意义的,并且会伤害到你编写最适合你的目的代码的能力。
也就是说,像GoF这样的阅读书会为你提供更多思考问题的方法,以便当你自己实现某个东西的时候,你将有更广泛的视angular去处理这个问题。
在你的情况下,如果在任何情况下使用单例都是有意义的,那么就直接前进吧。 如果“sorting”合适,而且必须以某种笨重的方式来实现,那么你需要提出一个新的解决scheme。 强迫一个不完美的模式有点像敲击一个圆孔的方形钉。
鉴于你说“这种方法是有效的,并certificate对我们的情况非常实际”,我认为你做得很好。
这里有一些好书:
“四人帮” – devise模式的经典之作
首先devise模式 – 我已经听到一些人推荐的替代scheme
是的,单身人士是不好的。 他们是不好的,因为他们所做的就是结合了两个属性,每个属性在95%的时间内都是不好的。 (这意味着平均来说,99.75%的单身人士是不好的)
GoF定义的一个单例是一个数据结构:
- 授予对象的全局访问权限
- 强制只有一个对象实例可以存在。
第一个通常被认为是一件坏事。 我们不喜欢全局variables。 第二个更微妙一点,但通常情况下,这是一个合理的强制执行的情况 。
有时,只有一个对象的实例才有意义。 在这种情况下,您select只创build一个。 你不需要一个单例来强制执行它。
通常,即使只有一个实例“有意义”,结果也是没有意义的。 迟早,你将需要不止一个logging器。 或者多个数据库。 或者你将不得不为每个unit testing重新创build资源,这意味着我们必须能够随意创build它们。 在我们了解后果之前,它过早地从我们的代码中删除了灵活性。
单身人士隐藏依赖关系并增加耦合(每个类可能依赖于单例,这意味着除非我们重用所有的单例,否则这个类不能在其他项目中重用),因为这些依赖并不是立即可见的(作为函数/构造函数参数),我们没有注意到它们,通常在创build它们的时候不会考虑它们。 只需拉一个单例很容易,它几乎作为一个局部variables,所有我们倾向于使用它们,一旦他们在那里。 这使得他们几乎不可能再次移除。 你最终可能不是用意大利面代码,而是用意大利面依赖图。 迟早你的失控依赖将意味着单身人士开始取决于对方,然后你得到循环依赖关系,当一个尝试初始化。
他们使unit testing非常困难。 (你如何testing一个函数调用单例对象上的函数?我们不希望实际的单例代码被执行,但我们如何防止呢?
是的,单身人士是不好的。
有时候,你真的想要一个全球化的。 然后使用全局的,而不是单身。
有时,非常非常非常罕见,您可能会遇到这样的情况:创build一个类的多个实例是一个错误,而不会导致错误。 (关于我能想到的唯一情况,即使是这样做,如果你代表一些硬件设备,你只有一个GPU,所以如果你要将它映射到你的代码中的对象,它会有道理,只有一个实例可以存在)。 但是,如果你发现自己处于这种情况下(并且再次强调,多个实例导致严重错误的情况,而不仅仅是“我不能想到多于一个实例的任何用例”的情况),然后执行这个约束,但是这样做也没有使对象全局可见。
在极less数情况下,这两个属性都是有用的。 但是我想不出一个情况,他们的结合会是一件好事。
不幸的是,很多人都认为“单身人士是符合OOP的全球人”。 不,他们不是。 除了引入其他一些完全不相关的问题外,他们仍然遇到与全局相同的问题。 绝对没有理由更喜欢单纯的旧式全球。
软件开发人员似乎很平均分成两个阵营,取决于他们是否偏爱理想主义的编码风格或实用的风格:
- 理想主义: 永远不要使用单身模式。
- 务实: 避免单身模式。
就个人而言,我赞成务实的态度。 有时违反规定是有道理的,但只有当你真正明白自己在做什么,并且愿意接受相关的风险。 如果您对以下关于您的具体使用情况的问题可以回答“是”,那么单例模式可以产生一些实际的好处。
- 是你的应用程序的外部单身? 数据库,排队服务和ESB都是单例模式的完全有效的macros示例。
- KISS:你的整个应用程序限于2-3个内部单身人士吗?
- DRY:那些单身人士本质上是全球性的,因此不得不将你的应用程序中的几乎所有对象都引用到其中? (例如,logging器或组件介体)?
- 你的单身人士是否仅仅依靠彼此和/或操作环境?
- 你是否确保每个单例都有正确的启动和closures序列,包括内存pipe理的考虑因素? 例如,“Grand Central”风格的线程池可能需要在main()中具有实例Run()和Shutdown()方法,这样才能保证任务只有在它们操作的对象处于有效状态时才能运行。
单身人士不杀害程序,程序员杀死程序。
就像任何编程构造一样,如果使用得当,你就不会在脚下自我射击。
推荐的书很好,但是当你可能select使用Singleton的时候,他们并不总是提供足够的背景经验。
这个经验只有当你发现Singleton是一个不好的select,当你需要有多个实例时,突然之间,注入对象引用无处不在。
有时候最好还是继续使用对象引用,但是,如果您不得不将它重构为不同的devise,那么您使用Singleton的事实确实有助于确定您将面临的问题的范围。 我相信这是一件非常好的事情,即只要有一个class级(即使devise不佳),也能看到class级变化的影响。
我们已经开始了一个基本面临同样问题的项目,那就是如何访问这个模型 ,特别是它的根本元素。 该项目不是一个Flex应用程序,而是一个戏剧! networking应用程序,但这并不重要。
在系统中有一个独特的对象是很好的,问题是如何访问它 。 因此关于单身人士的争论与依赖倒置 (DI)的概念以及如何获得物体有关。
DI的主要观点如下:
- 可testing性和嘲弄
- 从使用中解耦对象实例化(这可能导致生命周期pipe理)
- 关注点分离
DI的可能方法是(见Fowler的经典文章 ):
- 在方法参数中传递对象
- 服务定位器
- DI框架
在这个angular度看,单例模式只是一种服务定位器,例如Model.getInstance()
。
但是为了面对未来的变化提供最大的灵活性,对唯一对象的引用应该尽可能多地传递 ,并且只有在必要时才用Model.getInstance()
获得。 这也将产生更干净的代码。
在我看来,单身人士的使用直接表明了一个devise缺陷。 原因很简单,它允许一个绕过C ++中内置的正常对象创build和销毁机制。 如果一个对象需要对另一个对象的引用,它应该在构造时传入一个引用,或者在内部创build一个新的实例。 但是当你使用单例时,你明确地混淆了创build和拆卸周期。 一个相关的问题是控制一个单身人士的生命是非常困难的。 结果,包括通用单例实现的许多包也包括笨重的对象生存期pipe理器等等。 有时候我想知道这些是否仅仅是为了pipe理单身人士而存在。
基本上,如果你需要在很多地方使用一个对象,它应该在堆栈中最高的公共点显式创build,然后通过引用传递给每个使用它的人。 有时候人们会使用Singletons,因为他们在将多个parameter passing给新线程时遇到问题,但不要为此而明确定义线程参数,并以相同的方式将它们传递给新线程。 你会发现你的程序stream动得更干净,并且由于静态的初始化依赖或错误的拆卸而没有令人讨厌的惊喜。
单身人士肯定不坏。 他们有他们的用途,其中一些非常好。 单身人士往往被缺乏经验的开发人员过度使用,因为这往往是他们所学习的第一个devise模式,而且相当简单,所以他们不必考虑其含义就可以把它扔到各处。
每次你想使用一个单身人士,试着考虑你为什么这样做,以及使用这种模式的好处和坏处是什么。
单身人士确实有效地创build了一套全面的“东西”(数据或方法),我想大多数人会同意使用太多的全局variables并不是一个好主意。 课堂和面向对象的整体观点是把事物分成不连续的区域,而不是把所有东西都夹在一个巨大的全球空间中。
我发现,我倾向于比单身更倾向于从顶部传递需要的物体。 我在我的应用程序初始化阶段创build一次,并将其传递给所有需要访问它们的对象。 它模仿单身模式的“单创”部分,但没有“全局”部分。
一个单身人士的重点在于,对于那些只有1人存在的物体。 你提到一个数据控件集合的类。 也许可以认为,实际上,有些情况下应用程序可能需要创build2套数据控件类,所以也许在这种情况下强制执行一个单例是不太正确的。 相反,如果你在app init上创build了这些数据类,并将它们传递给它们,那么你将只创build1个集合,因为这是你当前的应用程序所需要的,但是在某些时候,如果你需要第二个集合你可以轻松地创build它们。 另外,如果数据控制类真的可以从应用程序的任何地方访问全球。 我认为不是,他们应该只能从较低级别的数据访问层访问。
有人推荐了GOF书。 我会说,是的,这是一本很好的书,但是先试着找一本关于总体架构的书,首先阅读2/3/n层devise,封装,抽象,这些原则。 这将给你一个更坚实的基础,了解GOF谈论的模式的适当用法。
[编辑:另一次单身变种可以是有用的是当你想要一个单一的访问点的东西,但实现细节可能实际上不止一件事。 调用者不需要知道,在封面下他们的单身对象的请求实际上是针对多个可用对象parsing的,并且返回一个。 我在想这里的线程池,在哪里使用,嘿,只要给我一个线程,我需要1,但我不在乎哪一个]
我知道这是一个古老的线索,但似乎没有人提到符合OP试图做的实际模式。 我相信他所描述的需要被称为中介模式 。 SourceMaking是学习/参考这种信息的绝佳网站。 绝对是我去介绍人们到软件模式的地方。 另外,不要认为任何devise模式本身就是好的或坏的概念是一个好主意。 他们都有自己的用处,只是学习何时何地使用它们就是把戏。 那些声称从不使用辛格尔顿的人对我来说,并不了解他们的用处。
不,他们不一定是坏的。
至于一本书,你需要从经典开始。
单身人士并不“那么糟糕”。 如果你有很多相关的单身人士,你可以使用工厂来replace/合并许多单身人士,而不会丢失任何你关心的东西,那么你应该这样做。
至于书, 好吧,有一个经典 。
我以为单身是好的 。
谷歌似乎相信单身人士是一个坏主意。
这并不意味着Google所做的一切都是完美的,或者说他们的每一个意见都是任何争论的结束,但是他们甚至写下这个Singleton探测器来解决这个问题。 做出自己的想法。