单例模式是设计模式中最简单的形式之一

单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限制实例化过程。这个方法应该是静态方法(类方法),因为让类的实例去生成另一个唯一实例毫无意义

意图:

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性:

当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

第一种(懒汉,线程不安全)

public class Singleton {

private static Singleton instance;

private Singleton (){}

public static Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

这种写法lazy loading很明显,但是致命的是在多线程不能正常工作

第二种(懒汉,线程安全)

public class Singleton {

private static Singleton instance;

private Singleton (){}

public static synchronized Singleton getInstance() {

if (instance == null) {

instance = new Singleton();

}

return instance;

}

}

这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。

第三种(饿汉)

public class Singleton {

private static Singleton instance = new Singleton();

private Singleton (){}

public static Singleton getInstance() {

return instance;

}

}

这种方式基于classloder机制避免了多线程的同步问题,不过,instance在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用getInstance方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化instance显然没有达到lazy loading的效果。

第四种(饿汉,变种)

public class Singleton {

private Singleton instance = null;

static {

instance = new Singleton();

}

private Singleton (){}

public static Singleton getInstance() {

return this.instance;

}

}

表面上看起来差别挺大,其实更第三种方式差不多,都是在类初始化即实例化instance。

第五种(静态内部类)

public class Singleton {

private static class SingletonHolder {

private static final Singleton INSTANCE = new Singleton();

}

private Singleton (){}

public static final Singleton getInstance() {

return SingletonHolder.INSTANCE;

}

}

public class Singleton {

private static class SingletonHolder {

private static final Singleton INSTANCE = new Singleton();

}

private Singleton (){}

public static final Singleton getInstance() {

return SingletonHolder.INSTANCE;

}

}

这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种和第四种方式不同的是(很细微的差别):第三种和第四种方式是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三和第四种方式就显得很合理。

第六种(枚举):

public enum Singleton {

INSTANCE;

public void whateverMethod() {

}

}

这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

第七种(双重校验锁)

public class Singleton {

private volatile static Singleton singleton;

private Singleton (){}

public static Singleton getSingleton() {

if (singleton == null) {

synchronized (Singleton.class) {

if (singleton == null) {

singleton = new Singleton();

}

}

}

return singleton;

}

}

这个是第二种方式的升级版,俗称双重检查锁定在JDK1.5之后,双重检查锁定才能够正常达到单例效果

优点

一、实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

二、灵活性

因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点

一、开销

虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

二、可能的开发混淆

使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

三、对象生存期

不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。

时间: 2024-10-25 18:30:58

单例模式是设计模式中最简单的形式之一的相关文章

大话设计模式C++版——简单工厂模式

简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类--依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class IOperation { public: IOperation() : m_nNuml(0), m_nNumr(0) {} virtual ~IOperation() {} virtual void SetNum(int nNuml = 0, int nNumr = 0) { m_nNuml = nN

JAVA设计模式中的单例模式

单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式.这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建.这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象.注意:1.单例类只能有一个实例.2.单例类必须自己创建自己的唯一实例.3.单例类必须给所有其他对象提供这一实例. 介绍 意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点.主

设计模式--简单工厂模式之在springboot中使用简单工厂模式

1.前言: 不了解简单工厂模式请先移步:在商城中使用简单工厂.在这里主要是对springboot中使用简单工厂模式进行解析. 2.问题: 什么是简单工厂:它的实现方式是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例. 然而在Spring中,在启动容器对时候会通过beanFactory先创建初始化我们要用的类. 一个是要在使用的时候去创建一个产品类,一个是预先已经加载好了我们要使用的对象,那我们要如何解决这个问题呢? 3.场景:在一个商城系统中,用

“只生一个娃”--设计模式中的单例模式

"只生一个娃"–设计模式中的单例模式(Singleton) 引言 ??被人问到什么是单例模式,突然回答不上来,似乎印象不深了.回去补了一下功课,突然明白了,原来在项目中一直使用的日志模块即采用了单例模式,只是熟视无睹,没有意识到罢了. ??所谓单例模式(Singleton),即指一个类只有一个实例(Instance),并给外界提供访问该实例的一个全局访问点. ??通常我们可以使用全局变量的方式来实现"只生一个娃",但更好的方法就是:让该类自身负责创建和保存它的唯一实

《设计模式其实很简单》

这几天囫囵吞枣看了下<设计模式其实很简单>,这本书通俗易懂,说了23种设计模式.自己看书比较仓促,看书时也不愿动脑子(这一直是致命缺点),先简单的抄下这些模式,希望日后能够回补. 设计模式中的六大设计原则 单一职责原则. 里氏代换原则. 开放-封闭原则. 依赖倒转原则. 合成/聚合复用原则. 迪米特法则. 下面的是一些模式,后面的解释个人觉得很精彩所以就加上了. 创建型模式 工厂方法模式----面向对象的工业时代. 抽象工厂模式----如果想开分厂. 单例模式----非你莫属. 建造者模式--

ASP.NET 设计模式中依赖倒置原则

依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象. B.抽象不应该依赖于具体,具体应该依赖于抽象. 依赖倒置原则 A.高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象. B.抽象不应该依赖于具体,具体应该依赖于抽象. 目录 1概述 2意图 3代码实现 4结构图 1概述编辑 所谓依赖倒置原则(Dependence Inversion Principle)就是要依赖于抽象,不要依赖于具体.简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现

设计模式中的关系在代码中的实现

我们都学过UNL,其中类图中有6类关系:泛华(继承).实现.关联.组合.聚合.依赖.由于他们之间也存在各种联系,我就将他们分为了4大类:依赖.关联.继承.实现. 整理如图: 从这个图中,我们就可以看出我是如何划分的了:聚合和组合是关联的特殊形式,所以就这样划分了. 我们知道,这6个关系的耦合的耦合度:继承=实现<依赖<关联<聚合<组合. 那么下一步,我们就看看,他们在设计模式的代码中是怎样实现的. 1.依赖关系 依赖关系的定义很绕口,其实说白了就是:一个对象依赖于另一个对象的服务.

OS 设计模式:MVC – 设计模式中的国王

原文:<iOS 设计模式系列:MVC – 设计模式中的国王> 模型(Model) 视图(View) 控制器(Controller) (MVC) 是 Cocoa 中的一种行为模块,并且也是所有 Cocoa 设计模式中使用最多的.在程序中按照它们的角色来分类这些对象并且鼓励你的基础代码也按照这个来划分. 这三种角色是: 模型:这是一种暂时保存你程序数据和定义如何操作它的对象.一个例子,在你的程序中 Album 类就是一个模型. 视图:这种对象是控制模型里的数据如何显示出来的,用户也可操作这些对象:

C#设计模式系列:简单工厂模式(Simple Factory)

1.简单工厂模式简介 1.1>.定义 简单工厂模式定义一个Factory类,可以根据参数的不同返回不同类的实例,被创建的实例通常有共同的父类. 简单工厂模式只需要一个Factory类. 简单工厂模式又称为静态工厂模式,Factory类为静态类或包含静态方法. 1.2>.使用频率  中 2.简单工厂模式结构 2.1>.结构图 2.2>.参与者 简单工厂模式参与者: ◊ Product:抽象产品类,将具体产品类公共的代码进行抽象和提取后封装在一个抽象产品类中. ◊ ConcretePr