定义

单例模式(Singleton Pattern)的定义如下:Ensure a class only has one instance, and provide a global point of access to it(确保某一个类只有一个实例,并且提供一个全局访问点来访问此实例)。在JVM应用中,单例模式表现为一个类在JVM中只有一个实例。一个相对合理的类图如下:

使用场景

  • 1、系统中需要一个共享的访问点或者共享数据,例如Web请求计数器。
  • 2、创建一个对象需要消耗的资源过多,例如IO、数据库资管等。
  • 3、需要定义大量的静态常量或者静态方法(例如工具类),可以考虑采用单例模式。

在JDK中典型的真实例子如下:

  • java.lang.Runtime#getRuntime()
  • java.awt.Desktop#getDesktop()
  • java.lang.System#getSecurityManager()

适用性

单例模式的优势

  • 采用单例模式的类能确保在一个应用中只有一个实例,减少了内存消耗以及创建或者销毁类实例时候的性能损耗。
  • 可以避免对资源的多重占用。
  • 可以设置应用的全局访问点,优化和共享资源访问。

单例模式的劣势

  • 单例模式一般没有接口或者基类,扩展困难,扩展必须修改类代码。
  • 紧密耦合的代码,对测试不利,简单来说就是不能Mock掉。
  • 单例模式违反单一责任原则,因为它既要保持"单例"又要顾及业务逻辑。

实现方式

懒汉方式

懒汉方式的关键字在于"懒",也就是懒加载(Lazy Load),一个很常见的使用方式就是双重检查锁定(Double-Check Locking):

public class Singleton {

	private static volatile Singleton INSTANCE = null;

	private Singleton(){

	}

	public static Singleton getInstance(){
if (null == INSTANCE){
synchronized (Singleton.class){
if (null == INSTANCE){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}

饿汉方式

饿汉方式的实现相对简单:

public class Singleton {

	private static volatile Singleton INSTANCE = new Singleton();

	private Singleton(){

	}

	public static Singleton getInstance(){
return INSTANCE;
}
}

静态内部类方式

使用静态内部类方式的好处是既可以实现延迟加载,又可以保证线程安全,它的实现如下:

public class Singleton {

	private Singleton(){

	}

	private static class InterClassHolder{
private final static Singleton INSTANCE = new Singleton();
} public static Singleton getInstance(){
return InterClassHolder.INSTANCE;
}
}

最佳实践-单元素枚举方式

《Effective Java》第2版中指出:单元素枚举类型是实现单例的最佳方式。这是因为,前面说到的三种实现方式都可以通过反射改变类的行为,但是枚举类型可以避免这个问题。建议在所有需要使用到单例模式的情况下直接使用单元素枚举方式实现单例:

public enum Singleton {

	INSTANCE;

	public void sayHello() {

	}
}

使用方式:Singleton.INSTANCE.sayHallo()

故事

Doge是公司里一个核心项目的开发组长,手下有十多个组员分别负责开发项目的不同模块。

Doge展示了一个日期工具类和它的使用情况:

public class DateUtils {

	public static String format(LocalDateTime target,String pattern){
return DateTimeFormatter.ofPattern(pattern).format(target);
} public LocalDateTime parse(String target,String pattern){
return LocalDateTime.parse(target, DateTimeFormatter.ofPattern(pattern));
}
} //调用情况
DateUtils.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
LocalDateTime target = new DateUtils().parse("2018-7-29 12:12:30","yyyy-MM-dd HH:mm:ss");

小黑贴了一下重写的工具类:

public enum DateUtils {

	SINGLETON;

	private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new HashMap<>();

	public String format(LocalDateTime target, String pattern) {
return getOrCreateFormatter(pattern).format(target);
} public LocalDateTime parse(String target, String pattern) {
return LocalDateTime.parse(target, getOrCreateFormatter(pattern));
} private DateTimeFormatter getOrCreateFormatter(String pattern) {
DateTimeFormatter formatter;
if (FORMATTER_CACHE.containsKey(pattern)) {
formatter = FORMATTER_CACHE.get(pattern);
} else {
formatter = DateTimeFormatter.ofPattern(pattern);
FORMATTER_CACHE.put(pattern, formatter);
}
return formatter;
}
} //调用
DateUtils.SINGLETON.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
LocalDateTime target = DateUtils.SINGLETON.parse("2018-7-29 12:12:30", "yyyy-MM-dd HH:mm:ss");

Doge拷贝了小黑的工具类代码,并且仿照这个类的逻辑完成了其他工具类的代码重构。

(本文完)

GOF设计模式之单例模式的更多相关文章

  1. GoF设计模式学习-单例模式

    1.目的 控制实例的个数,类设计者应该保证只有一个实例,不能将此责任[只有一个实例]强制交给类使用者. 2.整体实现 1.单线程单例模式的实现. using System; using System. ...

  2. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则

    加载类可以使用include.require.require_once三种中的任意一种,每个关键字都有两种方法,但是这种方法的缺点是需要加载多少个php文件,就要写多少个加载类的方法.一般也就需要加载 ...

  3. GOF设计模式特烦恼

    这段时间,学习状态比较一般,空闲时基本都在打游戏,和研究如何打好游戏,终于通过戏命师烬制霸LOL,玩笑了.为了和"学习"之间的友谊小船不翻,决定对以往学习过的GOF设计模式做一个简 ...

  4. OOAD-设计模式(二)之GRASP模式与GOF设计模式概述

    一.GRASP模式(通用责任分配软件模式)概述 1.1.理解责任 1)什么是责任 责任是类间的一种合约或义务,也可以理解成一个业务功能,包括行为.数据.对象的创建等 知道责任——表示知道什么 行为责任 ...

  5. GOF设计模式快速学习

    这段时间,学习状态比较一般,空闲时基本都在打游戏,和研究如何打好游戏,终于通过戏命师烬制霸LOL,玩笑了.为了和"学习"之间的友谊小船不翻,决定对以往学习过的GOF设计模式做一个简 ...

  6. Java 设计模式之单例模式(一)

    原文地址:Java 设计模式之单例模式(一) 博客地址:http://www.extlight.com 一.背景 没有太多原由,纯粹是记录和总结自己从业以来经历和学习的点点滴滴. 本篇内容为 Java ...

  7. python设计模式之单例模式(二)

    上次我们简单了解了一下什么是单例模式,今天我们继续探究.上次的内容点这 python设计模式之单例模式(一) 上次们讨论的是GoF的单例设计模式,该模式是指:一个类有且只有一个对象.通常我们需要的是让 ...

  8. 漫谈 GOF 设计模式在 Spring 框架中的实现

    原文地址:梁桂钊的博客 博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」.一群同频者,一起成长,一起精进,打破认知的局限性. 漫谈 GOF 设计模式在 Spring ...

  9. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

随机推荐

  1. js判断上传图片宽高及文件大小

    <input id="file" type="file"> <input id="Button1" type=" ...

  2. 洛谷——P1743 矩阵 III

    P1743 矩阵 III 题目背景 usqwedf 改编系列题. 题目描述 给定一个n*m的矩阵,问从左上角走到右下角有多少条路径. 输入输出格式 输入格式: 一行两个正整数 n,m 输出格式: 路径 ...

  3. RabbitMQ (十四) 普通集群

    上篇文章把单机集群搭建好了,可以开始验证普通集群的相关功能了. 我们首先在管理后台(15672,15673 都可以)添加一个用户,并用新用户登录,添加一个虚拟主机 由于是在一台机器上模拟集群,所以我们 ...

  4. AvalonJS学习笔记(一)

    一.关于AvalonJS avalon是国内的一个MVVM框架,是从knockout发展起来的 分为两个版本 avalon.js版本,支持IE6及非常老的标准浏览器.这里的标准浏览器特指W3C阵营中的 ...

  5. luogu P1047 校门外的树

    题目描述 某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1米.我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置:数轴上的每个整数点,即0,1,2,……,L,都种 ...

  6. 插头dp练习

    最近学了插头dp,准备陆续更新插头dp类练习. 学习论文还是cdq那篇<基于连通性状态压缩的动态规划问题>. 基本的想法都讲得很通透了,接下来就靠自己yy了. 还有感谢kuangbin大大 ...

  7. POJ 2404 Jogging Trails(最小权完美匹配)

    [题目链接] http://poj.org/problem?id=2404 [题目大意] 给出一张图,求走遍所有的路径至少一次,并且回到出发点所需要走的最短路程 [题解] 如果图中所有点为偶点,那么一 ...

  8. matlab2016b ubuntu命令行安装 + matconvnet的安装

    0. 下载安装包 下载的文件有Matlab 2016b Linux64 Crack.rar,R2016b_glnxa64_dvd2.iso,R2016b_glnxa64_dvd1.iso. 1. 拷贝 ...

  9. GNU ARM 汇编指令

    第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针.设置页表.操作 ARM的协处理器等.初始化完成后就可以跳转到C ...

  10. 读取bq26500电池电量 Driver

    bq26500是用于锂离子电池.锂聚合物电池充电.放电控制和监控的集成电路芯片.利用它能够准确提供电池充电.放电.电池温度.充放电电压.电池电量等相关数据.不须要外接微处理器參与电池充电.放电等相关数 ...