定义

单例模式(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. oracle常用函数整理

    oracle常用函数整理    1.绝对值.取余.判断数值正负函数    绝对值:ABS(n)        示例: SELECT ABS(100),ABS(-100),ABS('100') FROM ...

  2. 如何去除windows下文本的^M

    使用vi编辑,输入命令: :%s/^M/\r/g 用来把^M换成回车 注意的是^M要使用CTRL-V CTRL-M生成,而不是直接键入^M

  3. JQ简单操作Ajax笔记

    JQ对ajax进行了封装,底层$.ajax().第二层是.load(),$.get(),$.post().第三层是$.getScript()和$.getJSON(). load(url selecto ...

  4. Oracle concat

    如果要进行多个字符串的拼接的话,可以使用多个CONCAT()函数嵌套使用,上面的SQL可以如下改写:SELECT CONCAT(CONCAT(CONCAT('工号为',FNumber),'的员工姓名为 ...

  5. BZOJ 2212 [Poi2011]Tree Rotations(线段树合并)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2212 [题目大意] 给出一棵二叉树,每个叶节点上有一个权值,现在可以任意交换左右儿子, ...

  6. 【模拟退火】Petrozavodsk Winter Training Camp 2017 Day 1: Jagiellonian U Contest, Monday, January 30, 2017 Problem F. Factory

    让你在平面上取一个点,使得其到给定的所有点的距离和最小. 就是“费马点”. 模拟退火……日后学习一下,这是从网上扒的,先存下. #include<iostream> #include< ...

  7. 【推导】【数学期望】Gym - 101237D - Short Enough Task

    按照回文子串的奇偶分类讨论,分别计算其对答案的贡献,然后奇偶分别进行求和. 推导出来,化简一下……发现奇数也好,偶数也好,都可以拆成一个等比数列求和,以及一个可以错位相减的数列求和. 然后用高中数学知 ...

  8. win8 wamp 安装报错

    可是安装wamp的时候(http://www.wampserver.com/en/#download-wrapper)下载的是64位的,刚开始报 错xxx.dll文件丢失,好吧我把那个xxx.dll文 ...

  9. storm性能优化

    Storm 性能优化 目录 场景假设 调优步骤和方法 Storm 的部分特性 Storm 并行度 Storm 消息机制 Storm UI 解析 性能优化 场景假设 在介绍 Storm 的性能调优方法之 ...

  10. 手动清除或刷新Linux的Swap分区

    物理内存接近饱和时,系统会自动将不常用的内存文件转储到Swap中,但Swap使用率达30%的时候对系统性能可能有一定影响.但当物理内存重新释放时,储存在Swap分区的其它应用不会重新回到物理内存中,所 ...