设计模式第六天之单例模式

这次和大家分享一下设计模式中的单例模式。

说到单例模式,我相信大家都了解,简单说就是某个类在整个程序中只有一个对象。那为什么使用单例模式呢?什么场景使用单例模式呢?

我个人认为,在程序设计中,经过分析,某个类有一个对象已经可以满足要求,如果此时再加上这个类会消耗许多资源(包括内存开销大,创建对象耗时等),这个类就推荐使用单例来实现了。比如:数据库连接及相关操作,图片加载,缓存,线程池等等。使用单例模式也可以更好的实现共享资源。

那如何实现单例模式呢?在这里我和大家分享五种方式。在这五种方式中,都是以一个简单的计算器例子来说明,计算加减乘除的类对象明显在程序中只要有一个就可以了。在这里只是为了介绍这些方式实现。

饿汉模式

 1 /**
 2  * 饿汉模式实现单例模式
 3  * 好处:简单
 4  * 缺点:
 5  * 当类加载的时候就创建了对象而不管对象时候在使用
 6  * 造成资源的浪费
 7  * 当内存不足的时候,回收了静态对象,此时访问也会带来bug
 8  * @author wangpeiyu
 9  *
10  */
11 public class Hungry {
12     private static Hungry instance= new Hungry();
13     
14     private Hungry(){
15         
16     }
17     public Hungry getInstance(){
18         return instance;
19     }
20     public int add(int a,int b){
21         return a+b;
22     }
23     public int sub(int a,int b){
24         return a-b;
25     }
26     public int mul(int a, int b){
27         return a*b;
28     }
29     public float div(int a,int b)
30     {
31         return a/b;
32     }
33 }

 

懒汉模式

 1 /**
 2  * 懒汉实现单例模式
 3  * 好处:解决了线程安全,也做到了要使用的时候才创建对象
 4  * 缺点:每次要获取该对象的时候,都要进行线程同步,即使在instance已经赋值了之后
 5  * 还要进行线程同步,这就造成了不必要的时间浪费和资源浪费
 6  * @author wangpeiyu
 7  *
 8  */
 9 public class Lazy {
10     private static Lazy instance=null;
11     private  Lazy(){}
12     public synchronized static Lazy getInstance(){
13         if(instance==null){
14             instance = new Lazy();
15         }
16         return instance;
17     }
18     public int add(int a,int b){
19         return a+b;
20     }
21     public int sub(int a,int b){
22         return a-b;
23     }
24     public int mul(int a, int b){
25         return a*b;
26     }
27     public float div(int a,int b)
28     {
29         return a/b;
30     }
31 }

 

静态内部类方式

 1 /**
 2  * 静态内部类实现单例模式
 3  * 好处:线程安全、也达到了延迟加载、当加载单例类的时候并没有创建对象。
 4  * 缺点:内存不足,回收静态对象时,在访问会出现bug
 5  * 无法解决发序列化导致的对象重建
 6  * @author wangpeiyu
 7  *
 8  */
 9 public class StaticInClass {
10     
11     private StaticInClass(){
12         
13     }
14     public static StaticInClass getInstance()
15     {
16         return SingletonHolder.instance;
17     }
18     /**
19      * 静态内部类
20      * 主要的单例类的holder
21      * @author wangpeiyu
22      *
23      */
24     private static final class SingletonHolder{
25         private static final StaticInClass instance = new StaticInClass();
26     }
27     public int add(int a,int b){
28         return a+b;
29     }
30     public int sub(int a,int b){
31         return a-b;
32     }
33     public int mul(int a, int b){
34         return a*b;
35     }
36     public float div(int a,int b)
37     {
38         return a/b;
39     }
40 }

 

双重检查加锁方式

 1 /**
 2  * 双重检查加锁模式实现单例模式
 3  * 好处:延迟了加载、线程安全,而且也避免了在instance已经赋值的情况下,多线程还要
 4  * 同步造成的资源浪费和无意义的等待
 5  * 缺点:当反序列化时无法避免会重新创建对象的问题
 6  * @author wangpeiyu
 7  *
 8  */
 9 public class DCL {
10     private static DCL instance = null;
11     private DCL(){}
12     public static DCL getInstance(){
13         if(instance==null){
14             synchronized (DCL.class) {
15                 if(instance==null)
16                 {
17                     instance = new DCL();
18                 }
19             }
20         }
21         return instance;
22     }
23     public int add(int a,int b){
24         return a+b;
25     }
26     public int sub(int a,int b){
27         return a-b;
28     }
29     public int mul(int a, int b){
30         return a*b;
31     }
32     public float div(int a,int b)
33     {
34         return a/b;
35     }
36 }

 

枚举方式

 1 /**
 2  * 使用枚举实现单例
 3  * 好处:
 4  * 1.完全确保整个程序只有一个实例
 5  * 2.线程安全,因为枚举一旦定义结束,编译器就不允许我们再使用其构造器来创建任何实例了
 6  * 3.构造函数是private的,即使定义为public,一样为private
 7  * 4.自由序列化,这样即使在反序列化时也不会重新创建
 8  * @author wangpeiyu
 9  *
10  */
11 public enum EnumCaculate {
12     instance;
13     private EnumCaculate(){
14     }
15     public int add(int a,int b){
16         return a+b;
17     }
18     public int sub(int a,int b){
19         return a-b;
20     }
21     public int mul(int a, int b){
22         return a*b;
23     }
24     public float div(int a,int b)
25     {
26         return a/b;
27     }
28 }

 

    在这五种实现中,我个人比较推荐枚举实现和双重检查加锁实现。原因在每个类的代码中体现了。

posted @ 2016-11-19 23:34  于王令  阅读(95)  评论(0)    收藏  举报