【问题标题】:Is Monostate the good cousin of the evil Singleton?Monostate 是邪恶的 Singleton 的好表弟吗?
【发布时间】:2009-03-09 00:56:13
【问题描述】:

Singleton 绝对是最被滥用和滥用的模式之一。我们中的许多人曾在某一时刻感染过单胎炎。奇怪的是,它的近亲Monostate 不太出名,也很少使用。您对于 Monostate 的观点是?好还是一样坏?它是使用 Singleton 的更好选择吗?您是否也会像使用 Singleton 一样不鼓励使用它?

【问题讨论】:

  • 是否愿意描述任一模式以便我们更准确地讨论?

标签: design-patterns oop


【解决方案1】:

嗯,单态单例...所以它有完全相同的问题。

  • 测试
  • 隐藏依赖项
  • 不灵活
  • 线程安全
  • 全局状态难以确保正确性

【讨论】:

  • 总结得很好。 Monostate Singleton 通常都不是一个好主意。
  • Monostate 与 singleton 不同,否则我不会提出这个问题。 segueuserfiles.middlebury.edu/xp/SingletonAndMonostate.pdf
  • 在区分单态和单态时,本文停留在技术细节上——性能、多态性和语法——所有这些都是特定于 Java 实现的。它没有解决单态和单态之间的概念差异,因为没有。
  • 实现差异可能会对系统的其余部分产生影响,因此如果它们在概念上相同,我们就不能说 A 是 B。还希望您能详细说明您提出的几点:不灵活、难以确保正确性和隐藏依赖关系。
  • 不灵活:你永远不知道自己需要多少东西。今天有一台打印机吗?明天他们两个。
【解决方案2】:

根据Monostates的这个定义,是不是这个注:

“单调者与SingletonsAreEvil一样都是邪恶的。”

我不一定同意。基本前提是 Singletons 和 Monostates 是全局变量,既然 Globals 是邪恶的,那么 Singletons 和 Monostates 也一定是邪恶的。

这种推理的问题在于它没有考虑到为什么全局变量是邪恶的。全局变量是邪恶的,主要是因为它们是可以在本地范围之外意外访问的变量,类似于非类型化语言通常允许通过引用它们来创建变量。

Singleton 和 Monostates 不会导致相同类型的问题,因为几乎不可能“意外”引用全局静态,调用它的实例方法,然后使用该实例。

换句话说,全局变量是邪恶的,因为它们会导致微妙且难以察觉的问题。 Singletons 和 Monostates 不会导致相同类型的问题,因此出于相同的原因,我不认为它们是邪恶的,这是大多数人在这个论点中似乎出错的地方。

现在,单例和单态会导致其他类型的问题吗?当然。显然,TDD 的人讨厌他们,因为他们很难用自动化测试来正确测试。好的,很好,但是对于那些不使用 TDD 的人来说,这些问题不存在。

当然,单例可能会被滥用。仅仅为了避免传递实例而使用它们的人正在滥用它们。我认为 Monostates 比单例更好。

很多人提出工厂模式而不是单例,但我觉得工厂只是花哨的单例生成器。不,没有静态“实例”方法,但它基本上做同样的事情(当工厂创建单个实例对象时)。 Factory.Create 与 Singleton.Instance 没有什么不同。

编辑:

Singletons 和 Monostates 与 Globals 相当的一个方面是它们是共享的,因此不是线程安全的。如果你打算做多线程应用程序,这是一个问题,如果你知道这一点,你可以采取措施序列化对共享对象的访问。所以这可能是唯一一个通常认为所有三种类型都会造成麻烦的领域。

【讨论】:

  • 说得好。但有一件事,工厂不一定是单例发电机。事实上,大多数时候工厂是用来生成实际的类实例的。
  • 这就是为什么我说“当工厂创建单个实例对象时”。
  • 99% 的使用 factory 时,它被用作虚拟构造函数(例如,它根据传入的 id 返回其子类的实例之一),而不是作为单例生成器。所以 Factory.Create 几乎总是与 Singleton.Instance 不同。
【解决方案3】:

Monostate 最大的问题是它可能会导致使用它的人感到困惑。一般来说,如果您创建一个对象的新实例,您希望它只是一个新实例,具有自己的状态和生命周期。我通常认为意外行为是一件坏事,所以我更喜欢单例,只是因为你知道使用它会得到什么。

至于任何一种模式是否是邪恶的,单例往往会被滥用,但所有其他模式、switch 语句、for 循环或您想提及的任何其他内容也是如此。

【讨论】:

    【解决方案4】:

    仅仅因为不使用模式怎么样?

    更新:滥用单例是因为人们添加了没有理由的模式。它通常会添加任意约束而无济于事。使用单态 w/o 理由可能危害较小,但没有更多理由。如果存在多个实例,如果宇宙不会崩溃,那么不要使用模式强制它 - 只需创建一个实例。

    【讨论】:

    • 我不同意。如果软件要演变成真正的构建块格式,那么我们需要标准化做事的方式,类似于结构工程师标准化桥梁或建筑设计的各个部分的方式。如果可能,应始终使用自己的模式。
    • 这个问题并不建议人们应该为了模式而使用模式。模式不是一种工具,它是在软件构建中一次又一次出现的同一个主题。如果你在你的日常代码设计并了解其优缺点,它将帮助您制作更好的软件。
    • “不要使用模式强制执行”似乎是因为我们使用模式强制执行它的任何一种方式 - 在您的情况下是“仅创建一个实例”的模式。只创建一个实例也不是免费的,这可能意味着需要添加方法或方法签名来传递共享信息。
    • 我的方式,创建另一个实例很简单,例如当您决定让显示适配器代码支持第二个监视器时。
    • @MM: 模式应该在更简单的时候使用而不是自己滚动
    【解决方案5】:

    您为什么认为人们会不鼓励使用单例?对 Singleton 进行全面概括就像对 goto、全局变量等进行全面概括。他们都有一个地方。这些东西都不是“邪恶的”,它们的滥用并不会使它们不好用,只是意味着它们需要正确使用。

    【讨论】:

    • 人们确实不鼓励单身人士,以至于谷歌有一个工具可以将他们从员工编写的任何 Java 代码中删除!它们当然有它们的用途(主要是缓存/资源处理),但从表面上看,它们是全局变量,它们使测试代码成为一场噩梦。
    • 我在测试单例时从来没有遇到过问题。是什么让他们变成了噩梦?
    • 同上 - 如果使用不当,大多数特性/模式/功能都会被滥用;它不会使它们本质上是“邪恶的”。
    • Boon:这是一个错误的类比,根本不是我要说的。将单例(充其量是方便但最糟糕的是笨拙的东西)与可以杀死数百万人的东西进行比较有点幼稚。单例用得好,没有人会死。
    • 我不是在概括,我是在反对那些东西是“邪恶”的概括。它们不是,它们只是经常被误用或过度使用。实际上,它更像是一把刀而不是炸弹。当然,你可以用它杀人,但它也有合法用途。以后不要那么夸张了。
    【解决方案6】:

    这是 Gamma、Helm、Johnson 和 Vlissides 所著《设计模式:可重用的面向对象软件的元素》第 127 页的节选。

    在以下情况下使用单例模式

    • 一个类必须只有一个实例,并且客户端必须可以从一个众所周知的访问点访问它
    • 当唯一的实例应该可以通过子类化来扩展,并且客户端应该能够在不修改其代码的情况下使用扩展的实例

    是否真的因为单例被滥用和误解而变得邪恶?

    【讨论】:

      【解决方案7】:

      与 Monostate 的区别在于,您需要较少了解对象的实现才能使用它。换句话说,您无需调用对象的 getInstance 方法 ( Singleton s = Singleton::getInstance; s.Method(); ) 即可获得对对象的引用,因此您节省了一些击键,您只需使用普通语言结构(单态毫秒;ms.Method();)。确实是一条细线。

      每个编程语言结构都可能被标记为邪恶,因为每个编程语言结构都可能被滥用。

      当合理使用时,我认为两者都不是“邪恶”或“好”。

      【讨论】:

        【解决方案8】:

        一个具有单个实例但没有全局访问权限的类怎么样:

        public class SingleInstance
        {
            private static boolean exhausted = false;
        
            public SingleInstance()
            {
                if (exhausted)
                {
                    throw new IllegalStateException("only one instance allowed");
                }
                exhausted = true;
        
                [...]
            }
        
            [...]
        }
        

        这避免了 Singleton 和 MonoState 的问题,同时它强制并清楚地传达了只有一个实例。

        【讨论】:

          猜你喜欢
          • 2011-12-07
          • 2011-01-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-11-18
          • 2010-11-26
          • 2020-08-10
          相关资源
          最近更新 更多