当前位置: 首页 > 编程笔记 >

深入解析Java的设计模式编程中单例模式的使用

陆晓博
2023-03-14
本文向大家介绍深入解析Java的设计模式编程中单例模式的使用,包括了深入解析Java的设计模式编程中单例模式的使用的使用技巧和注意事项,需要的朋友参考一下

定义:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
类型:创建类模式
类图:

类图知识点:
1.类图分为三部分,依次是类名、属性、方法
2.以<<开头和以>>结尾的为注释信息
3.修饰符+代表public,-代表private,#代表protected,什么都没有代表包可见。
4.带下划线的属性或方法代表是静态的。
5.对类图中对象的关系不熟悉的朋友可以参考文章:设计模式中类的关系。
单例模式应该是23种设计模式中最简单的一种模式了。它有以下几个要素:

  • 私有的构造方法
  • 指向自己实例的私有静态引用
  • 以自己实例为返回值的静态的公有的方法

来看一个简单的例子:

package com.wolf.action;
import java.util.HashMap;
import java.util.Map;
public class demo {
 public static void main(String args[]) throws InstantiationException,
  IllegalAccessException, ClassNotFoundException {
 System.out.println(Son.getInstance().getName());
 System.out.println("我是谁");
 }
}
class Son extends Father {
 private String name = "儿子";
 final String CLASS = "demo";
 protected String getName() {
 return this.query("aaa");
 }
 public static Son getInstance() throws InstantiationException,
  IllegalAccessException, ClassNotFoundException {
 // 这里必须是全局路径 否则无法找到
 return (Son) instance("com.wolf.action.Son");
 }
}
class Father {
 private static Map<String, Object> instance = new HashMap<String, Object>();
 private String name = "父类";
 protected void Fatcher() {
 System.out.println("我是父类");
 }
 protected String query(String sql) {
 return sql + "has been done";
 }
 public static Object instance(String objname)
  throws InstantiationException, IllegalAccessException,
  ClassNotFoundException {
 if (instance.get(objname) == null
  || !(instance.get(objname) instanceof Father)) {
  instance.put(objname, Class.forName(objname).newInstance());
 }
 return instance.get(objname);
 }
}

        单例模式根据实例化对象时机的不同分为两种:一种是饿汉式单例,一种是懒汉式单例。饿汉式单例在单例类被加载时候,就实例化一个对象交给自己的引用;而懒汉式在调用取得实例方法的时候才会实例化对象。代码如下:
饿汉式单例

public class Singleton { 
  private static Singleton singleton = new Singleton(); 
  private Singleton(){} 
  public static Singleton getInstance(){ 
    return singleton; 
  } 
} 

懒汉式单例

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

单例模式的优点:

  • 在内存中只有一个对象,节省内存空间。
  • 避免频繁的创建销毁对象,可以提高性能。
  • 避免对共享资源的多重占用。
  • 可以全局访问。

适用场景:由于单例模式的以上优点,所以是编程中用的比较多的一种设计模式。我总结了一下我所知道的适合使用单例模式的场景:

  • 需要频繁实例化然后销毁的对象。
  • 创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
  • 有状态的工具类对象。
  • 频繁访问数据库或文件的对象。
  • 以及其他我没用过的所有要求只有一个对象的场景。

单例模式注意事项:

  • 只能使用单例类提供的方法得到单例对象,不要使用反射,否则将会实例化一个新对象。
  • 不要做断开单例类对象与类中静态引用的危险操作。
  • 多线程使用单例使用共享资源时,注意线程安全问题。

关于java中单例模式的一些争议:

单例模式的对象长时间不用会被jvm垃圾收集器收集吗
        看到不少资料中说:如果一个单例对象在内存中长久不用,会被jvm认为是一个垃圾,在执行垃圾收集的时候会被清理掉。对此这个说法,笔者持怀疑态度,笔者本人的观点是:在hotspot虚拟机1.6版本中,除非人为地断开单例中静态引用到单例对象的联接,否则jvm垃圾收集器是不会回收单例对象的。
对于这个争议,笔者单独写了一篇文章进行讨论,如果您有不同的观点或者有过这方面的经历请进入文章单例模式讨论篇:单例模式与垃圾收集参与讨论。
 
在一个jvm中会出现多个单例吗
        在分布式系统、多个类加载器、以及序列化的的情况下,会产生多个单例,这一点是无庸置疑的。那么在同一个jvm中,会不会产生单例呢?使用单例提供的getInstance()方法只能得到同一个单例,除非是使用反射方式,将会得到新的单例。代码如下

Class c = Class.forName(Singleton.class.getName()); 
Constructor ct = c.getDeclaredConstructor(); 
ct.setAccessible(true); 
Singleton singleton = (Singleton)ct.newInstance(); 

这样,每次运行都会产生新的单例对象。所以运用单例模式时,一定注意不要使用反射产生新的单例对象。
 
懒汉式单例线程安全吗
        主要是网上的一些说法,懒汉式的单例模式是线程不安全的,即使是在实例化对象的方法上加synchronized关键字,也依然是危险的,但是笔者经过编码测试,发现加synchronized关键字修饰后,虽然对性能有部分影响,但是却是线程安全的,并不会产生实例化多个对象的情况。
 
单例模式只有饿汉式和懒汉式两种吗
        饿汉式单例和懒汉式单例只是两种比较主流和常用的单例模式方法,从理论上讲,任何可以实现一个类只有一个实例的设计模式,都可以称为单例模式。
 
单例类可以被继承吗
        饿汉式单例和懒汉式单例由于构造方法是private的,所以他们都是不可继承的,但是其他很多单例模式是可以继承的,例如登记式单例。
 
饿汉式单例好还是懒汉式单例好
        在java中,饿汉式单例要优于懒汉式单例。C++中则一般使用懒汉式单例。
单例模式比较简单,在此就不举例代码演示了。

 类似资料:
  • 本文向大家介绍深入解析C++设计模式编程中解释器模式的运用,包括了深入解析C++设计模式编程中解释器模式的运用的使用技巧和注意事项,需要的朋友参考一下 解释器模式(interpreter),给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 解释器模式需要解决的是,如果一种特定类型的问题发生的频率足够高,那么可能就值得将该问题的各个实例表述为一个简单语

  • 本文向大家介绍实例解析Ruby设计模式编程中Strategy策略模式的使用,包括了实例解析Ruby设计模式编程中Strategy策略模式的使用的使用技巧和注意事项,需要的朋友参考一下 今天你的leader兴致冲冲地找到你,希望你可以帮他一个小忙,他现在急着要去开会。要帮什么忙呢?你很好奇。 他对你说,当前你们项目的数据库中有一张用户信息表,里面存放了很用户的数据,现在需要完成一个选择性查询用户信息

  • 本文向大家介绍解析C#设计模式之单例模式,包括了解析C#设计模式之单例模式的使用技巧和注意事项,需要的朋友参考一下   单例模式(Singleton),故名思议就是说在整个应用程序中,某一对象的实例只应该存在一个。比如,一个类加载数据库中的数据到内存中以提供只读数据,这就很适合使用单例模式,因为没有必要在内存中加载多份相同的数据,另外,有些情况下不允许内存中存在多分份相同的数据,比如数据过大,内存

  • 本文向大家介绍详解Ruby设计模式编程中对单例模式的运用,包括了详解Ruby设计模式编程中对单例模式的运用的使用技巧和注意事项,需要的朋友参考一下 简介       单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。使用工厂方法来限

  • 本文向大家介绍深入剖析Ruby设计模式编程中对命令模式的相关使用,包括了深入剖析Ruby设计模式编程中对命令模式的相关使用的使用技巧和注意事项,需要的朋友参考一下 命令模式是对象行为型使用率比较高的设计模式,别名:Action(动作),Transaction(事务) 意图: 将一个请求封装为一个对象,从而使你可对不同的请求进行参数化;对请求排队或记录请求日志,以及支持可取消的操作 这里所谓的“不同

  • 本文向大家介绍浅谈Java编程中的单例设计模式,包括了浅谈Java编程中的单例设计模式的使用技巧和注意事项,需要的朋友参考一下 写软件的时候经常需要用到打印日志功能,可以帮助你调试和定位问题,项目上线后还可以帮助你分析数据。但是Java原生带有的System.out.println()方法却很少在真正的项目开发中使用,甚至像findbugs等代码检查工具还会认为使用System.out.print