Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 什么';不使用单例模式是错误的_Java_Design Patterns_Singleton - Fatal编程技术网

Java 什么';不使用单例模式是错误的

Java 什么';不使用单例模式是错误的,java,design-patterns,singleton,Java,Design Patterns,Singleton,我正在从我的电子书(Head First Design Patterns)中阅读关于singleton模式的内容,我知道如果您只需要某个类的一个实例,使用该模式是合适的。 但是我对这本电子书中的问题介绍有点小麻烦 (是的,我想我可以在这里引用一部分!) 巧克力工厂众所周知,所有现代巧克力工厂都有计算机控制的巧克力锅炉。委员会的工作 锅炉是把巧克力和牛奶放进去,烧开,然后 然后将它们传递到制作巧克力的下一阶段。 这里是 Choc-O-Holic,Inc.工业实力的控制器等级 巧克力锅炉。检查代码;

我正在从我的电子书(Head First Design Patterns)中阅读关于singleton模式的内容,我知道如果您只需要某个类的一个实例,使用该模式是合适的。
但是我对这本电子书中的问题介绍有点小麻烦
(是的,我想我可以在这里引用一部分!)

巧克力工厂
众所周知,所有现代巧克力工厂都有计算机控制的巧克力锅炉。委员会的工作 锅炉是把巧克力和牛奶放进去,烧开,然后 然后将它们传递到制作巧克力的下一阶段。
这里是 Choc-O-Holic,Inc.工业实力的控制器等级 巧克力锅炉。检查代码;你会注意到他们试图 要非常小心,以确保坏事情不会发生,如排水 500加仑未煮沸的混合物,或在锅炉冷却时加满 已经满了,或者沸腾了一个空锅炉

是的,这是他们的问题:

Choc-O-Holic在确保不发生坏事方面做得不错 发生了,你不觉得吗?再说一次,你可能会怀疑如果两个 巧克力一旦松动,一些非常糟糕的事情就会发生。
如果不止一个巧克力的例子,事情会怎么发展 是在应用程序中创建的吗

因此,当我们这样做时,问题将“发生”:

ChocolateBoiler boiler1 = new ChocolateBoiler(),
 boiler2 = new ChocolateBoiler();
//...
但是我看到这两个实例控制着它自己的行为,它们独立运行(因为这里没有静态字段)。
所以它们单独运行,对其他实例没有影响。
我想知道这个问题是关于非法状态的,或者当一个实例运行并对其他实例产生影响时可能会发生什么事情(不正确的程序行为、过度使用资源或 不一致的结果”,来自电子书),但不在此

所以,
这里可能会出现什么问题?
,这只是一个浪费的实例吗

如果两块巧克力松动,一些非常糟糕的事情就会发生 发生

我想看看那些坏事情是怎么发生的

#编辑1: 谢谢大家帮助我我知道我的问题是什么,
当我调用
boiler2=newchocolaboolbooler()
时,
boiler2
实例仍然引用与bolder1相同的boiler,是吗?

我第一次认为
新巧克力锅炉()
类似于买一个新锅炉:)
这是关于概念的,我是这里的新手

使用单件模式的全部意义与(或可以被视为)有关和冲突管理。单一真相来源当然也是一种冲突管理

单例模式的另一个方面是,出于效率原因,需要尽量减少不必要的重复和/或(重新)初始化

例如,两个单独的实例会在同一个资源上发生冲突,这取决于所使用的应用程序和平台(例如多线程),可能会导致各种问题,如死锁、无效状态等


资源是一个(单例),因此此资源的管理器或驱动程序需要考虑到这一点,以避免在同一资源上发生潜在冲突(见上文)。

您似乎不理解此示例试图解释的概念。
Chocketbool
不是一个真正的锅炉,它是一个java类

但是,这个类可以用来指示一个硬件(一个真正的锅炉控制器)执行一些操作。如果您错误地拥有两个
chocketboolbool
实例,并且您错误地使用这两个实例来指示同一个锅炉控制器,那么显然您遇到了麻烦


在我的前一段中有两个“错误”,你可能会说,如果你做的事情总体上是“错误的”,那么你无论如何都会遇到麻烦。但是如果设计糟糕的单例,错误可能不会那么明显。如果你序列化和反序列化一个没有处理序列化问题的单例以保持唯一性,然后尝试to使用该实例来加热锅炉,您可能会烧坏锅炉。

单例模式有几个问题需要注意。 让我们考虑两个不同的单例:

1) 无状态单态

此单例将没有字段成员,并且只将方法作为服务提供给外部世界

public class StatelessSingleton {

    private static final StatelessSingleton INSTANCE = new StatelessSingleton();

    private StatelessSingleton() {

        // exists to defeat instantiation
    }


    public void service() {
        //...
    }

    public void anotherService() {
        //..
    }

    public StatelessSingleton getInstance() {
        return INSTANCE;
    }
}
出于性能和可读性的考虑,这种类型的单例通常最好用只有静态方法的类来代替。例外情况可能是在实现模式(如策略)时,您需要将某些接口实现为无状态算法,因为缓存此实现是有意义的。要实现接口,您显然需要需要一个实例

2) 全州选举

public class StatefullSingleton {

    private int a = 3;

    private static final StatefullSingleton INSTANCE = new StatefullSingleton();

    private StatefullSingleton() {

        // exists to defeat instantiation
    }


    public void service() {
        // do some write operation on a
    }

    public void anotherService() {
        // do some read operation on a
    }

    public StatefullSingleton getInstance() {
        return INSTANCE;
    }

}
现在,谈谈单身人士的问题:

如果这两个单例的实现都不好,则可能会导致多个实例。如果在java中使用双重检查锁定来确保只存在一个单例实例,则会出现这种情况:

class Foo {
    private Helper helper;
    public Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }

    // other functions and members...
}
有大量可用的资源讨论为什么这在java中不起作用,因此无需在此重复

避免双重检查锁定问题的一种方法是如上所示的私有构造函数和对instance+getter的静态引用

第二个问题,具体到StatefullSingleton是,如果您的服务方法不同步,多个线程可能会破坏这种单例的状态。在您的示例中,如果不同的工作线程同时加注和排放锅炉,则可能会出问题


第三个问题是序列化。鉴于Singleton实现了java.io.Serializable接口,这可能会导致反序列化过程中出现多个Singleton。为了避免在反序列化时创建新对象,必须实现
readResolve

只有一个boiler。尝试两种方法时会发生什么
class Foo {
    private Helper helper;
    public Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }

    // other functions and members...
}