顾名思义,单例模式就是只有一个实例,不管怎样,使用了单例模式的类在系统中只有一个对象被访问到。Java中单例模式定义:“一个类有且仅有一个实例,并且这个类会自行实例化,实例化时候的对象可以提供给整个系统。”
动机: 对于系统中的某些类来说,只有一个实例是很重要的,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
实现过程:
显然单例模式的要点有三个;一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例
,就是以下三点:
1、单例模式的类只提供私有的构造函数(通过控制构造函数来显示类的实例的生成过程 构造函数私有化 只能有本类来创建本类的实例)
2、类定义中含有一个该类的静态私有对象的引用private static 单例类的引用名=new 单例类的方法( );这种构造模式下仅仅在这个部分执行了一次构造函数。
3、该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。(这个相当于提供给外部的一个方法 通过这个方法 可以获得这个类的实例)
因为是static的 该类对象只有一个实例,不会没new一次该实例,又因为构造函数是私有的,在定义类的时候已经生成了单一的实例变量。只能通过 Classname.单例类的引用名 这样的方式来访问这个实例变量 无法再生成新的实例变量了(构造函数私有),又因为是私有的,仅仅能通过共有的函数入口来进行访问,外部的类无法对该实例进行修改。
内在的逻辑思路:
要求只能生成一个实例—>将构造函数私有化—>保证外部的程序无法通过new来产生新的实例对象—>在外部无法生成实例对象—>没法通过对象来调用实例方法—>只能通过类方法来返回一个实例对象—>静态方法只能访问静态属性—>所以在类内部生成的实例属性也要是static类型的
三个关键点:
1、构造函数私有
2、静态成员变量引用自身类的实例对象
3、向外部提供getinstance函数来访问内部的static实例
具体代码如下:
package com.designpatten.SingletonPatten; /* * 实现了一个单例模式 */ public class SingletonPatten { //初始化函数 private SingletonPatten() { System.out.println("creat a new instance"); } private int number=0; private static SingletonPatten singlepatten=new SingletonPatten(); public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public static SingletonPatten getinstance(){ System.out.println("evoke the instance"); //注意调用私有static属性的时候不用加this 因为static属性属于整个类 return singlepatten; } } /* * 可以看出来 仅仅有一个实例 调用了一次构造函数creat a new instance (仅仅被调用了一次) * 虽然每次都生成了新的实例 但是只有一个实例 */ public class Test { public static void main (String[]args) { SingletonPatten s1=SingletonPatten.getinstance(); System.out.println(s1.getNumber()); s1.setNumber(1); SingletonPatten s2=SingletonPatten.getinstance(); System.out.println(s2.getNumber()); s2.setNumber(2); SingletonPatten s3=SingletonPatten.getinstance(); System.out.println(s3.getNumber()); System.out.println(s1==s2); System.out.println(s2==s3); } }
执行结果:
creat a new instance
evoke the instance
0
evoke the instance
1
evoke the instance
2
true
true
可以看出来 s1 s2 s3三个引用指向的是相同的地址空间,仅仅生成了一个实例。