首页 > 代码库 > 最常用的设计模式(单例模式)

最常用的设计模式(单例模式)

  记得刚开始涉足程序的时候, 去笔试 ,发现有一个笔试题经常粗线,写一个单例模式的基本实现, 当时没研究设计模式也就不知为何物,

  到今日  , 才发现它已成为我日常开发最常用的一种设计模式。

  我写的所有设计模式的代码都会用java 呈现, 虽然第一个学习的是c++但是 最开始作为工作的是java,并且有点偏好java

  单例模式 , 意思就是 整个系统仅只有此类的一个实力, 当然这只是狭义的单例,经常看到变种的单例是允许,创建指定数量的实例的

  单例模式是一种创建型模式。 它是优化的一种策划, 避免重复创建销毁一个对象(创建销毁对象是有开销的), 有点像对象池的概念。

  

  我写博文  纯粹是对自己所了解的东西的一个回顾,  不保证权威性。  仅希望 迷途的新手能在我的博文中 有所收获,我也尽量 用我最简单的语言 去描述 我对 很多东西的理解、(这段话会在我的每一个博文里面出现 因为 我不是一个看了书 做笔记的博客, 而是我进行思考的博客 ,当然也希望大牛可以批评指正)

 

  下面给出一个最简单的单例的实现

 1 public class HelloSingleton {
 2     
 3     private static HelloSingleton w_Instance = new HelloSingleton();
 4 
 5     //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
 6     private HelloSingleton(){
 7         
 8     }
 9     
10     public static HelloSingleton getInst(){
11         return w_Instance;
12     }
13 }

这一种单例模式被成为饿汉模式, 其实意思就是开始的时候就实例好了 对象, 缺点是没有做到延迟加载 (延迟加载是一种优化策略,在需要的时候再去加载)这个用起来比较简便

 

然后下面是 另外一种单例模式,懒汉模式

 

public class HelloSingleton {
    
    private static HelloSingleton w_Instance;

    //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
    private HelloSingleton(){
        
    }
    
    public static HelloSingleton getInst(){
        if(w_Instance == null){
            w_Instance = new HelloSingleton();
        }
        return w_Instance;
    }
}
public class HelloSingleton {
    
    private static HelloSingleton w_Instance;

    //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
    private HelloSingleton(){
        
    }
    
    public static HelloSingleton getInst(){
        if(w_Instance == null){
            w_Instance = new HelloSingleton();
        }
        return w_Instance;
    }
}

网上看到,或者大多数人都是如此写懒汉模式的, 这种写法在单线程环境下是安全的, 但是在多线程环境下 会造成生成多个实例的问题

比如现成A正在访问 getInst()方法 ,线程A读到w_Instance 为null ,创建该类对象并返回,线程B正好在此时也访问getInst方法,此时现成A构造的实例现成B无法看见,因为多线程环境中非同步代码快无法保证共享变量的可见性。所以该写法是有问题的, 调整为如下则不会在多线程环境下出现创建多个实例的问题。

 1 public class HelloSingleton {
 2     
 3     private static HelloSingleton w_Instance;
 4 
 5     //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
 6     private HelloSingleton(){
 7         
 8     }
 9     
10     public static synchronized HelloSingleton getInst(){
11         if(w_Instance == null){
12             w_Instance = new HelloSingleton();
13         }
14         return w_Instance;
15     }
16 }
 1 public class HelloSingleton {
 2     
 3     private static HelloSingleton w_Instance;
 4 
 5     //定义一个私有的构造函数,确保在该类的外部无法生成类的实例
 6     private HelloSingleton(){
 7         
 8     }
 9     
10     public static synchronized HelloSingleton getInst(){
11         if(w_Instance == null){
12             w_Instance = new HelloSingleton();
13         }
14         return w_Instance;
15     }
16 }

java用synchronized保证同步代码快。 同步代码快 既保证 变量的原子性,也保证变量的可见性。

 

上面是最简单的两种单例的写法,但是为了扩展 , 还是介绍一些 其他的 常见的单例的写法。

 

effective   java作者 推崇的 用枚举的方式实现的 singleton 

 

1 public enum HelloSingleton {
2     
3     Instance;
4     
5 }

额 你没有看错 就是这个样子的  , 起初 看到这个代码 , 我也很疑惑 , 这个是单例吗, 但是确实它也实现了单例 模式。 java的枚举不同于 c++ , c#等语言, java的枚举是用对象实现的, 所以此枚举里 仅有一个对象

它的优点是这么介绍的 优点:不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

 

第四种单例,采用静态内部类型, 我的同时  很多次 跟我讲 他觉得java的内部类真的是很扯淡的设计, 不知道是干什么用的, 但是我个人感觉java的内部类让java 语言用起来更灵活, 比如我 不想让别人使用的类 仅仅想在一个对象里面使用的类 ,就可以用private 定义一个 内部类 , 别人无须知道 内部实现。 更好的实现封装的思想,

代码示意图如下

 

 1 public class HelloSingleton {
 2      private static class SingletonHolder
 3      {
 4          private final static HelloSingleton w_Instance = new HelloSingleton();
 5      }
 6      
 7      private HelloSingleton(){
 8          
 9      }
10      
11      public static HelloSingleton getInst(){
12          return SingletonHolder.w_Instance;
13      }
14 }

 

此类型看起来比较晦涩  好像绕了不烧 , 这样写的好处是:加载时不会初始化静态变量INSTANCE,因为没有主动使用,达到延迟加载

 

还有一个类型就不介绍了 ,因为个人 基本没用到过,   感觉自己最常用的就是第二种, 懒汉式 , 单例。

 

设计模式, 单例, 就是这么简单 。 

 

关于单例的变种你可以这么想 , 有的时候   你会想让单例 生成指定数量的 实例, 具体实现就是在 类里面加个 数量, 然后每次getInst 的时候去判断 是否达到最大数量, 如果达到就不在生成新的实例 ,如果没有,就生成新的实例返回, 好了 单例 就这么简单, 感觉没什么好说的 就写到这里