设计模式:
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、
以及解决问题的思考方式。设计模免去我们自己再思考和摸索。就像是经典
的棋谱,不同的棋局,我们用不同的棋谱。【套路】
一、单例模式的概述
单例设计模式,就是采用一定的方法,保证在整个软件系统运行过程中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,
- ① 我们首先必须将类的构造器的访问权限设置为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 饿汉式
-
饿汉式:
坏处:对象加载时间过长,占用内存空间;
好处:天然是线程安全的; -
懒汉式:
好处:延迟对象的创建,节约内存空间;
坏处:线程不安全(目前写法是不安全的,后期加锁以后,也可以变成安全的)