定义

单例模式(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. python之IO model

    一.事件驱动模型 在介绍协程时,遇到IO操作就切换,但什么时候切换回来,怎么确定IO操作结束? 很多人可能会考虑使用“线程池”或“连接池”.“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的 ...

  2. logstash的grok正则匹配规则文件

    文件路径:logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.0/patterns/grok-patterns 在线调试g ...

  3. python--flask框架的安装和简单使用(转)

    原文地址:http://blog.csdn.net/xiaowu8858892520/article/details/54428196

  4. 【(博弈)dfs序+树状数组】BZOJ2819-Nim

    [题目大意] 普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可以不取.谁不能取谁输.这个游戏是有必胜策略的.现在对每一堆编号1,2,3,4,...n,在 ...

  5. git远程仓库创建及权限管理(一)单个项目

    最近接手公司git权限管理,既然负责此事个人觉得应该深入学习下,不仅为当前工作也为进一步发展.网上查找了一番,找到了完整的教程,所以这里不再一步一步描述,具体链接已给出,本文只对操作过程中遇到的问题的 ...

  6. 浙南联合训练赛 H - The number of positions

    Petr stands in line of n people, but he doesn't know exactly which position he occupies. He can say ...

  7. LinkedList源码及解析

    package java.util; import java.util.function.Consumer; /** * LinkedList基于链表实现 * 实现了List.Deque.Clonea ...

  8. NHibernate 之持久化类、拦截器 (第二篇)

    一.持久化类中成员标量的要求 作为被NHibernate使用的持久化类,必须满足以下几点要求: 1.声明读写属性 在NHibernate的使用中,持久化类的成员变量必须声明对应的属性,NHiberna ...

  9. Java8新语言特性

    Java8简明指南 欢迎来到Java8简明指南.本教程将一步一步指导你通过所有新语言特性.由短而简单的代码示例,带你了解如何使用默认接口方法,lambda表达式,方法引用和可重复注解.本文的最后你会熟 ...

  10. oracle 性能优化建议

    原则一:注意WHERE子句中的连接顺序: ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHER ...