如何构建创造性设计模式:单例模式
Posted 程序你好
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何构建创造性设计模式:单例模式相关的知识,希望对你有一定的参考价值。
单例设计模式是一种软件设计模式,它将类的实例化限制为一个对象。与其他创造性设计模式(如抽象工厂)相比,单例构建器模式将创建一个对象,并且还将负责只存在该对象的一个实例。
当创建一个单例类时,有一些问题需要记住:
如何确保一个类只有一个实例?
如何方便地访问类的惟一实例?
类如何控制实例化?
如何限制类的实例数量?
例如,假设我们有一个发送消息的类 — the Messenger
class:
package com.gkatzioura.design.creational.singleton;
public class Messenger {
public void send(String message) {
}
}
但是,我们希望消息过程仅由Messenger类的一个实例来处理。让我们假设一个场景:Messenger类打开一个tcp连接(例如,XMPP),并且为了发送消息,必须保持连接的存在。每次必须发送消息时,打开新的XMPP连接会非常低效。
因此,我们将继续并使Messenger类成为单例。
package com.gkatzioura.design.creational.singleton;
public class Messenger {
private static Messenger messenger = new Messenger();
private Messenger() {}
public static Messenger getInstance() {
return messenger;
}
public void send(String message) {
}
}
如您所见,我们将messenger构造函数设置为private,并使用静态变量初始化一个messenger。静态变量是类级变量,其中内存分配只在类被加载到内存中时发生一次。在此过程中,我们确保Messenger类将只实例化一次。getInstance方法将在调用静态messenger实例时获取它。
显然,前面的方法有其优点和缺点,我们不必担心线程安全性,并且只有在加载Messenger类时才会创建实例。但是,它缺乏灵活性。让我们考虑将配置变量传递给Messenger构造函数的场景。您将发现使用以前的方法是不可能的。
解决方案是在getInstance方法上实例化Messenger类。
package com.gkatzioura.design.creational.singleton.lait;
public class Messenger {
private static Messenger messenger;
private Messenger() {}
public static Messenger getInstance() {
if(messenger==null) {
messenger = new Messenger();
}
return messenger;
}
public void send(String message) {
}
}
上述方法在某些情况下可能有效,但在多线程环境中实例化类的情况下,它会忽略线程安全性。
使类线程安全的最简单方法是同步getInstance方法。
package com.gkatzioura.design.creational.singleton.lait;
public class Messenger {
private static Messenger messenger;
private Messenger() {}
public synchronized static Messenger getInstance() {
if(messenger==null) {
messenger = new Messenger();
}
return messenger;
}
public void send(String message) {
}
}
上面的代码可以正常工作。至少,messenger的创建将是同步的,不会创建重复的副本。这种方法的问题是,只有在创建对象时才需要同步。使用上述代码将导致不必要的开销。
另一种方法是使用双重检查锁定方法。现在,双重检查锁定需要特别小心,因为很容易在错误的实现中选择正确的实现。最好的方法是使用volatile关键字实现延迟加载。
package com.gkatzioura.design.creational.singleton.dcl;
public class Messenger {
private static final Object lock = new Object();
private static volatile Messenger messenger;
private Messenger() {}
public static Messenger getInstance() {
if(messenger==null) {
synchronized (lock) {
if(messenger==null) {
messenger = new Messenger();
}
}
}
return messenger;
}
public void send(String message) {
}
}
通过使用volatile关键字,我们可以防止volatile对象的写入对任何先前的读写进行重新排序,防止volatile的读取对任何后续的读写进行重新排序。另外,互斥对象用于实现同步。
总之,我们创建了一个对象,并确保该对象只有一个实例。我们确保在多线程环境中实例化对象不会出现任何问题。
以上是关于如何构建创造性设计模式:单例模式的主要内容,如果未能解决你的问题,请参考以下文章