单例模式:Singleton
单例模式英文定义:
Ensure a class has only one instance,and provide a global point of access to it.
单例模式中文定义:
确保一个类只有一个实例,而且自行实例化并向整个应用提供这个实例。
单例模式优点:
1、在内存中只有一个实例,减少了内存开支;
2、只生成一个实例,减少了系统的性能开销;
3、可以避免对资源的多重占用;
4、可以在系统设置全局的访问点,优化和共享资源访问,比如数据库的映射处理。
单例模式缺点:
1、单例模式要求“自行实例化”并提供单一实例,接口或抽象类不能被实例化,所以单例模式一般没有接口,扩展很困难,只能通过修改代码来实现。当然,在特殊情况下,单例模式可以实现接口或被继承,这个根据具体开发环境判断。
2、单例模式与单一职责原则冲突。单一职责原则规定:一个类应该只实现一个逻辑,而不关心它是否是单例的,而单例模式则把“要单例”和业务逻辑融合了一个类中处理。
单例模式使用场景:
1、要求生成唯一序列号时;
2、需要定义大量的静态常量和静态方法(比如工具类)时;
3、创建一个对象需要消耗的资源过多时;
4、在整个项目中需要一个共享访问点或共享数据时。
单例模式通用方法:
饿汉式单例模式:
package com.hongke;
/**
* @author chengjunyu
* @classname Singleton
* @description 饿汉式单例模式
* @date 2020/8/1 15:38
*/
public class Singleton {
private static final Singleton singleton = new Singleton();
//通过private修饰词限制产生多个对象
private Singleton() {
}
//通过该方法获取一个单例对象,此处使用的是【饿汉式单例模式】
public static Singleton getSingleton() {
return singleton;
}
//单例模式要处理的业务
public void doSomething() {
System.out.println("我是饿汉式单例模式");
}
}
懒汉式单例模式:
package com.hongke;
/**
* @author chengjunyu
* @classname Singleton
* @description 懒汉式单例模式
* @date 2020/8/1 15:38
*/
public class Singleton {
private static Singleton singleton = null;
//通过private修饰词限制产生多个对象
private Singleton() {
}
//通过该方法获取一个单例对象,此处使用的是【懒汉式单例模式】
public static Singleton getSingleton() {
if(null == singleton) {
singleton = new Singleton();
}
return singleton;
}
//单例模式要处理的业务
public void doSomething() {
System.out.println("我是懒汉式单例模式");
}
}
单例模式使用注意事项:
单例模式分为【饿汉式单例模式】和【懒汉式单例模式】,低并发的情况下两者一致,高并发情况下使用懒汉式单例模式可能会导致线程不安全。因此建议使用饿汉式单例模式,当然,也可以通过synchronized关键字去修饰懒汉式单例模式中的getSingleton()方法,不过这种方式明显不如饿汉式单例模式来的方便。
单例模式示例:
很多公司的老板或创始人只有一位,比如说华为创始人,我们都知道就是任正非先生,现在华为发布了一款新的产品,记者来到了华为公司进行采访,并且表示要采访华为创始人任正非先生,那么在程序中便可通过以下案例进行。
Boss.java
package com.hongke;
/**
* @author chengjunyu
* @classname Boss
* @description 老板单例类
* @date 2020/8/1 14:50
*/
public class Boss {
private static String bossName = "任正非";
private static final Boss boss = new Boss();
private Boss() {
}
public static Boss getInstance() {
return boss;
}
public void say() {
System.out.println("我是华为创始人:" + bossName);
}
}
Reporter.java
package com.hongke;
/**
* @author chengjunyu
* @classname Reporter
* @description 记者类
* @date 2020/8/1 14:54
*/
public class Reporter {
public static void main(String[] args) {
Boss boss = Boss.getInstance();
boss.say();
}
}
打印结果如下:
单例模式扩展:
在一些特殊场景下,需要一个类能产生固定数量的对象。比如说华为的轮值董事长,目前是郭平、徐直军、胡厚崑,每个轮值董事长管理华为一段时间,但他们都是华为的轮值董事长。此时,华为又发布了一款新产品,记者又来采访了,这次他们不再去麻烦任正非先生了,他们就去找了华为的轮值董事长,但他们并不挑剔,只要是华为的轮值董事长,对他们来说都是可以的,那么在程序中便可通过以下案例进行。
RotatingChairman.java
package com.hongke;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author chengjunyu
* @classname RotatingChairman
* @description 轮值董事长
* @date 2020/8/1 17:00
*/
public class RotatingChairman {
//轮值董事长名称
private static List<String> nameList = new ArrayList<>();
//轮值董事长集合列表
private static List<RotatingChairman> chairmanList = new ArrayList<>();
//轮值董事长序号
private static int numberOfChairman = 0;
//静态方法中直接创建三位轮值董事长
static {
chairmanList.add(new RotatingChairman("郭平"));
chairmanList.add(new RotatingChairman("徐直军"));
chairmanList.add(new RotatingChairman("胡厚崑"));
}
private RotatingChairman() {
}
private RotatingChairman(String name) {
nameList.add(name);
}
//随机出现一位轮值董事长
public static RotatingChairman getRotatingChairman() {
Random random = new Random();
numberOfChairman = random.nextInt(chairmanList.size());
return chairmanList.get(numberOfChairman);
}
public void say() {
System.out.println("我是华为轮值董事长:"+nameList.get(numberOfChairman));
}
}
Reporter.java
package com.hongke;
/**
* @author chengjunyu
* @classname Reporter
* @description 记者类
* @date 2020/8/1 14:54
*/
public class Reporter {
public static void main(String[] args) {
// Boss boss = Boss.getInstance();
// boss.say();
//来了10个记者
for(int i = 0; i < 10; i++) {
RotatingChairman rotatingChairman = RotatingChairman.getRotatingChairman();
rotatingChairman.say();
}
}
}
打印结果如下: