Java设计模式之单例模式(Singleton pattern)

Java设计模式之单例模式(Singleton Pattern)

[导读]

       目前Java的设计模式(Design Pattern)有23种,设计模式作为提高代码的复用性并解决同一类问题的科学工具,就如同东方人使用筷子吃饭,西方人使用刀叉吃西餐一样,这里的筷子、刀叉便是一种生活中的“设计模式”,当我们吃东西的时候不必过多考虑,拿起筷子撸就可以了。Java的设计模式也是基于一些共性问题做了代码优化总结,以便于开发者的使用。

        本文就设计模式之一的单例模式(Singleton Pattern)进行原理分析。

[提出问题]

       我们想象这样一个问题,假设现在我们需要用Java来记录太阳的姓名和年龄,并且可以查询和修改这两个变量,如何实现?

       一般来说,我们需要创建一个“太阳”类,来封装这个对象并对其成员变量进行操作:(代码如下)

 

 1 public class Sun {
 2     private String name;
 3     private int age;
 4     
 5     public String getName() {
 6         return name;
 7     }
 8     public void setName(String name) {
 9         this.name = name;
10     }
11     public int getAge() {
12         return age;
13     }
14     public void setAge(int age) {
15         this.age = age;
16     }
17 }
Sun

        但是我们会发现一个问题,实际操作中我们可以无限的进行new sun();操作,这表示这个太阳不止一个,且每个太阳的姓名和年龄都可以不一样,但我们的需求是“只有一个太阳,只对一个太阳进行操作”。又该如何解决呢?

[解决“太阳不唯一”的问题]

        学过static的童鞋应该都想到了可以将变量静态化,这样做确实可以让数据共享从而保证唯一性。但任然可以无限进行new sun();操作。另一个问题是如果变量不止两个,而是超级多,我们就需要对每个变量都静态化,这样就会产生各种各样的问题。所有,人们为了解决:保证一个类只有一个实例对象的问题,而设计出了单例模式。

[单例模式の原理]

         接着上面“唯一的太阳”的问题,我们来具体分析一下该如何解决:

         思路:

         既然要保证一个类只能有一个实例对象,那么怎么才能保证对象唯一呢?

          1、首先外界不能使用new来创建对象,不然就不能保证只有一个对象。

          2、无法使用new,所以需要类本身自己创建好这个唯一的对象

          3、也需要对外提供调用该对象方法

         实现步骤:

          1、不让外界创建对象,即不能进行new操作,而new操作的是类的构造函数,所以让构造函数私有化即可。

          2、在类内部new一个该类型的对象最为唯一的实例对象。

          3、对外暴露一个调用对象的方法,返回类型是该类类型。

          4、值得注意的一个问题是:因为我们已经无法对该类进行new操作,所以只能让方法和对象静态化,用类名.方法名来直接调用。

           具体代码如下:

 1 public class Sun {
 2     private String name;
 3     private int age;
 4 
 5     //步骤2:在本类中new这个唯一的实例对象(步骤4:静态化)
 6     private static Sun instance = new Sun();
 7 
 8     //步骤1:构造函数私有化
 9     private Sun(){
10         
11     }
12 
13     //步骤3:对外暴露方法(步骤4:静态化)
14     public static Sun getInstance(){
15         return instance;
16     }
17     
18     public String getName() {
19         return name;
20     }
21     public void setName(String name) {
22         this.name = name;
23     }
24     public int getAge() {
25         return age;
26     }
27     public void setAge(int age) {
28         this.age = age;
29     }
30 }
Sun

 

        这就是单例模式的设计思路,也是一种单例模式写法:我们把按照这种思路的写法称之为“饿汉式”。另外还有 “懒汉式”等写法,但都大同小异,建议使用“饿汉式”即可,因为“懒汉式”在 多线程中存在安全隐患。

[测试一下]

        我们对刚才创建的“唯一的太阳”(即用单例模式设计的类sun)进行测试,看看是不是真的唯一?

 

 1 public class SunTest {
 2 
 3     public static void main(String[] args) {
 4 
 5         Sun s1 = Sun.getInstance();
 6         Sun s2 = Sun.getInstance();
 7         s1.setName("日"); //嘿嘿(*^▽^*)
 8         s2.setAge(11);
 9         System.out.println("两个Sun引用是否指向同一个对象呢?");
10         System.out.println(s1.equals(s2));
11 
12          System.out.println("s2调用了s1设置的sun的name:"+s1.equals(s2));
13          System.out.println("s1调用了s2设置的sun的age:"+s1.equals(s2));
14     }
15 
16 }
SunTest

 

         运行结果:

         

         结果很给力,我们实现了这个“唯一的太阳”。^_^

[一些细节]

          单例模式的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。

          为什么我们要设置成语变量私有化(Private)呢?我们一般希望通过get和set来获取和设置成员变量,以达到对数据的可控性。所以在开发过程中一般情况下我们都应该默认私有化成员变量,这样有助于控制数据,如上文的类Sun:如果我们有一个需求是:输入的年龄不能为负数。这样我们就可以修改setAge()方法:

1 private int setAge(int age){
2      if(age >= 0)
3           return this.age = age;
4 }

           这就是对数据的具备可控性的一个小栗子。

posted @ 2017-10-07 21:39  风之之  阅读(304)  评论(0)    收藏  举报