模拟场景:一个王朝只能有一个皇帝,臣子每天见的都是同一个皇帝
Emperor:
1 package com.zqz.dp.singleton; 2 /** 3 * @author Qin 场景:皇帝类,一个王朝只能有一个皇帝 4 */ 5 public class Emperor { 6 private static final Emperor emperor = new Emperor(); // 初始化一个皇帝,以后该王朝至始至终都是改皇帝 7 private Emperor() {// 构造方法私有化,外部无法产生第二个皇帝 8 } 9 public static Emperor getInstance() { 10 return emperor; // 取得唯一的那个皇帝的对象 11 } 12 public void doSomething() { //皇帝开始发号施令 13 System.out.println("我是皇帝我最大"); 14 } 15 }
Minister
1 package com.zqz.dp.singleton; 2 /** 3 * @author Qin 4 * 臣子类,每天都要参拜皇帝,那么肯定参拜的是同一个皇帝 5 */ 6 public class Minister { 7 public static void main(String[] args) { 8 Emperor emperor=Emperor.getInstance(); //取得唯一的皇帝实例 9 for(int day=0;day<3;day++){ //开始朝拜 10 emperor.doSomething(); 11 } 12 } 13 }
在上面的操作中,对单例设计还有两种说法,一种是饿汉式,一种是懒汉式。所谓的饿汉式就是在定义具体类实例的时候就立即进行了实例化的操作。而懒汉式就是说一开始不进行实例化,在进行具体操作的时候判断是否进行了实例化,如果未进行实例化就进行实例化的操作。
修改Emperor
1 package com.zqz.dp.singleton; 2 /** 3 * @author Qin 场景:皇帝类,一个王朝只能有一个皇帝 4 */ 5 public class Emperor { 6 private static final Emperor emperor = null; // 声明一个皇帝,未初始化 7 private Emperor() {// 构造方法私有化,外部无法产生第二个皇帝 8 } 9 public static Emperor getInstance() { 10 return emperor; // 取得唯一的那个皇帝的对象 11 } 12 public void doSomething() { //皇帝开始发号施令 13 if(this.emperor ==null){ //如果还未初始化 14 this.emperor=new Emperor(); 15 } 16 System.out.println("我是皇帝我最大"); 17 } 18 }
单例模式的优点:
在具体的开发中建议使用饿汉式,因为懒汉式在高并发的时候可能会出现实例化两次的时候,也就是说在高并发的时候,一个线程在判断发现该对象未实例化然后进行实例化的操作时(还未实例化),另一个线程进来发现该对象没实例化,所以也进行实例化的操作,这样就导致了出现两个实例的操作。
1、 因为只有一个实例,所以减少了内存的开支。
2、 减少系统性能的开销
3、 避免对资源的多重占用
4、 资源共享
单例模式的缺点:
1、 单例模式一般没有接口,所以扩展麻烦。之所以没有接口,是因为构造方法私有化,但接口或抽象类一般都不能直接进行实例化,要子类进行实例化的操作。
2、 对测试不利,未开发成单例,无法进行测试。
3、 与单一职责原则冲突。
单例模式的使用场景:
1、 要求生成唯一的序列的环境;
2、 在整个项目中需要建立一个共享资源点,即要资源共享;
3、 创建一个对象需要消耗的资源过多;
4、 需要定义大量的静态变量或者静态方法的环境;
单例设计模式的拓展
场景:一个王朝出现两个皇帝
Emperor
1 package com.zqz.dp.prototype; 2 import java.util.ArrayList; 3 import java.util.Random; 4 /** 5 * @author Qin 场景:皇帝类,一个王朝存在两个皇帝 6 */ 7 public class Emperor { 8 private static int maxEmperorNum=2; //定义一个常量,该王朝只有两个皇帝 9 private static ArrayList<Emperor> emperors=new ArrayList<Emperor>(); //arrayList容器存放多个皇帝对象 10 private String name; //定义每个皇帝的名号 11 private static int num; //标志,返回的数组下标 12 static{ //静态块初始化信息 13 for(int i=0;i<maxEmperorNum;i++){ 14 emperors.add(new Emperor("皇帝"+i)); //生成两个皇帝实例 15 } 16 } 17 private Emperor() {// 构造方法私有化,外部无法产生第二个皇帝 18 } 19 private Emperor(String name) {// 重载构造器,同时给每个皇帝赋名号 20 this.name=name; 21 } 22 public static Emperor getInstance() { 23 Random random=new Random(); //random类,随机产生数字,用来随机取出不同的皇帝实例 24 num=random.nextInt(maxEmperorNum); //取得随机数 25 return emperors.get(num); //返回皇帝实例 26 } 27 public void doSomething() { //皇帝开始发号施令 28 System.out.println("我是"+this.name+",有事起奏,无事退朝。"); 29 } 30 }
Minister
1 package com.zqz.dp.prototype; 2 /** 3 * @author Qin 4 * 臣子类,每天都要参拜皇帝,那么肯定参拜的是同一个皇帝 5 */ 6 public class Minister { 7 public static void main(String[] args) { 8 for(int i=0;i<5;i++){ //循环5次,表示五个大臣 9 Emperor emperor=Emperor.getInstance(); //每个大臣参拜的不一定是同一个皇帝 10 System.out.print("第"+i+"个大臣参拜的是:"); 11 emperor.doSomething(); 12 } 13 } 14 }