设计模式——单例模式(Singleton)

本文详细介绍了设计模式中的单例模式,包括其概述、优点、应用场景及两种实现方式:懒汉式和饿汉式。单例模式确保一个类只有一个实例,通过私有构造器和静态方法实现。其优点在于减少系统资源开销,适用于计数器、日志应用、数据库连接池等场景。懒汉式和饿汉式的区别在于对象创建的时间点,懒汉式在需要时创建,饿汉式在类加载时创建。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计模式:

设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、
以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典
的棋谱,不同的棋局,我们用不同的棋谱。【套路】


一、单例模式的概述

单例设计模式,就是采用一定的方法,保证在整个软件系统运行过程中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,

  • ① 我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生该类的对象了(但在类的内部仍可产生对象);
  • ② 因为在类的外部无法得到对象,因此必须提供一个该类的静态方法用以在类的内部创建对象并返回【必须是静态的,因为要能用类直接调用;若不是静态的,则需要先创建对象,才能通过对象调用方法,但是单例模式并不允许外部创建对象】;
  • ③ 静态方法只能访问类中的静态成员变量,因此,存储对象的属性也必须是静态的

二、单例模式的优点

由于单例模式只生成一个实例,减少了系统性能的开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时,直接产生一个单例对象,然后永久驻留内存的方式来解决。【不再频繁的创建、销毁对象,从而节约了系统资源】


三、单例模式的应用场景

例如:

  • 网站的计数器,一般也是单例模式实现,否则难以同步。
  • 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志
    文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库
    资源。
  • 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置
    文件数据,都生成一个对象去读取。
  • Application 也是单例的典型应用
  • Windows的Task Manager(任务管理器)就是很典型的单例模式
  • Windows的Recycle Bin (回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

四、单例模式的两种形式

1. 懒汉式

【一开始类加载时,并不创建对象,而是设置为null,等到调用getInstance()方法来获取对象时,才去new并返回(即,什么时候需要,什么时候才去new,“懒”)】

代码实例:(程序中银行Bank通常只有一个,适合使用单例模式)

public class SingletonTest1 {
	public static void main(String[] args) {
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		
		System.out.println(bank1); //com.atguigu.java2.Bank@15db9742
		System.out.println(bank2); //com.atguigu.java2.Bank@15db9742
		System.out.println(bank1 == bank2); //true
	}
}

/**
 * 懒汉式:
 * 	一开始并没有对唯一实例进行new,而是初始为null,调用getInstance()方法时,才创建对象并返回
 */
class Bank{
	//2. 声明当前类的对象,但不初始化
	private static Bank instance = null; //(要在静态方法中调用,因此也必须声明为静态的)
	
	//1. 私有化类的构造器(为了避免在类的外面调用构造器,因为只要能调用,调用一次就会创建一个对象)
	private Bank(){}
	
	//3. 提供公共的静态方法,返回类的对象
	//(既然外部无法创建对象,就必须在内部提供一个方法来创建对象;而且要无需通过对象、直接通过类就能调用,因此是static的)
	public static Bank getInstance(){
		if(instance == null){
			instance = new Bank();
		}
		
		return instance;
	}
}

2. 饿汉式

【一上来类加载时,就对唯一实例(成员变量)进行new创建对象,调用getInstance()方法时直接返回实例(即,一上来就new,“饿”)】

/**
 * 饿汉式:
 * 	一开始就对唯一实例进行new,创建对象,调用getInstance()方法时直接返回实例
 */
class Bank1{
	//2. 声明当前类的对象,并初始化
	private static Bank1 instance = new Bank1();
	
	//1. 私有化构造方法
	private Bank1(){}
	
	//3. 提供公共的静态方法,返回类的实例
	public static Bank1 getInstance(){
		return instance;
	}
}

若单纯追求"单例"的话,其实如下写法也满足单例模式,但是通常一个类是需要有很丰富的操作的,需要在方法中使用语句来把控,如下方式则显得过于简陋

class Bank1{
	//2. 声明当前类的对象,并初始化
	public static final Bank1 instance = new Bank1();
	//设置为public,外界可以直接调用;为了防止外部修改,设置为final
	
	//1. 私有化构造方法
	private Bank1(){}
}

3. 区分:懒汉式 vs 饿汉式

  • 饿汉式:
    坏处:对象加载时间过长,占用内存空间
    好处:天然是线程安全的;

  • 懒汉式:
    好处:延迟对象的创建,节约内存空间;
    坏处:线程不安全(目前写法是不安全的,后期加锁以后,也可以变成安全的)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值