问题分析:
首先来明确一个问题,那就是在某些情况下,有些对象,我们只需要一个就可以了,比如,一台计算机上可以连好几个打印机,但是这个计算机上的打印程序只能有一个,这里就可以通过单例模式来避免两个打印作业同时输出到打印机中,即在整个的打印过程中我只有一个打印程序的实例。
简单说来,单例模式(也叫单件模式)的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个(当然也可以不存在)。
单例模式的定义:
确保某一个类有且只有一个实例,而且自行实例化并向整个系统提供整个实例
单例模式的使用场景:
确保某个类有且只有一个对象的场景,避免产生多个对象那个消耗过多的资源,或者某种对象类型的对象只有应该有且只有一个。
实现单例模式的关键点:
1,构造函数不对外开放,一般为Private
2,通过一个静态方法或者枚举返回单例类对象
3,确保单例类的对象有且只有一个,尤其是在多线程环境下
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
简单点呢就是:
首先,单例模式使类在程序生命周期的任何时刻都只有一个实例,
然后,单例的构造函数是私有的,外部程序如果想要访问这个单例类的话,
必须通过 GetInstance()来请求(注意是请求)得到这个单例类的实例。
懒汉模式:
public class Singleton { private Singleton(){};//私有构造函数:使外部不能使用构造函数来创建该对象 private static Singleton mSingleton=null;//私有静态常量没有实例化:private保证只能内部访问该变量,static与类有关 public static synchronized Singleton getSingleton(){//公有静态放法:加了一个同步 if(mSingleton=null) { mSingl eton=new Singleton(); } return mSingleton; }
首先这个 Singleton 类会在在第一次调用 getSingleton()时创建一个实例,并将这个实例的引用封装在自身类中,然后以后调用 getSingleton()时就会判断这个 Singleton 是否存在一个实例了,如果存在,则不会再创建实例。而是调用以前生成的类的实例,这样下来,整个应用程序中便就只存在一个实例了。
优点:每次只在使用时被实例化,
缺点:每次调用getSingleton()都要进行同步,造成不必要的同步开销,不建议使用
饿汉模式:
public class Singleton { private Singleton(){};//私有构造函数:使外部不能使用构造函数来创建该对象 private static final Singleton mSingleton=new Singleton();//私有静态常量并实例化:private保证只能内部访问该变量,static与类有关,final一旦初始化就不能修改 public static Singleton getSingleton(){//公有静态放法:只能通过此方法来获取静态常量 return mSingleton; }
例子:一个公司只有一个CEO,可以有几个VP,无数个员工,但CEO只有一个
Staff.java
public class Staff{ public void work(){ //干活 } }
VP.java
public class VP extends Staff { @Override public void work(){ //管理员工 } }
CEO.java
package com.hust.singleton; //CEO 单例模式(饿汉模式) public class CEO extends Staff{ private CEO(){};//私有构造函数:使外部不能使用构造函数来创建该对象 private static final CEO mCEO=new CEO();//私有静态常量并实例化:private保证只能内部访问该变量,static与类有关,final一旦初始化就不能修改 public static CEO getCEO(){//公有静态放法:只能通过此方法来获取静态常量 return mCEO; } @Override public void work(){ //管理VP } } /*1.饿汉模式 * public class Singleton { private Singleton(){};//私有构造函数:使外部不能使用构造函数来创建该对象 private static final Singleton mSingleton=new Singleton();//私有静态常量并实例化:private保证只能内部访问该变量,static与类有关,final一旦初始化就不能修改 public static Singleton getSingleton(){//公有静态放法:只能通过此方法来获取静态常量 return mSingleton; } * 2,懒汉模式,优点:每次只在使用时被实例化,缺点:每次调用getSingleton()都要进行听不,造成不必要的同步开销,不建议使用 * public class Singleton { private Singleton(){};//私有构造函数:使外部不能使用构造函数来创建该对象 private static Singleton mSingleton=null;//私有静态常量没有实例化:private保证只能内部访问该变量,static与类有关 public static synchronized Singleton getSingleton(){//公有静态放法:加了一个同步 if(mSingleton=null) { mSingl eton=new Singleton(); } return mSingleton; } * * * */
Company.java
package com.hust.singleton; import java.util.ArrayList; import java.util.List; public class Company { private List<Staff> mAllStaffs=new ArrayList<Staff>(); public void addStaff(Staff mStaff) { mAllStaffs.add(mStaff); } public void showAllStaffs() { for(Staff mStaff:mAllStaffs){ System.out.println("Obj:"+mStaff.toString()); } } }
Test.java
package com.hust.singleton; import java.security.PublicKey; public class TestSingleton { /** * @param args */ public static void main(String[] args) { Company mCompany=new Company(); //CEO对象只能通过getCEO函数获取 Staff mCeo1=CEO.getCEO(); Staff mCeo2=CEO.getCEO(); mCompany.addStaff(mCeo1); mCompany.addStaff(mCeo2); //通过new创建VP对象 Staff mVP1=new VP(); Staff mVP2=new VP(); mCompany.addStaff(mVP1); mCompany.addStaff(mVP2); //通过new创建Staff对象 Staff mStaff1=new Staff(); Staff mStaff2=new Staff(); Staff mStaff3=new Staff(); mCompany.addStaff(mStaff1); mCompany.addStaff(mStaff2); mCompany.addStaff(mStaff3); mCompany.showAllStaffs(); } }
输出结果:
Obj:com.hust.singleton.CEO@15db9742 Obj:com.hust.singleton.CEO@15db9742//只有一个实例 Obj:com.hust.singleton.VP@6d06d69c Obj:com.hust.singleton.VP@7852e922 Obj:com.hust.singleton.Staff@4e25154f Obj:com.hust.singleton.Staff@70dea4e Obj:com.hust.singleton.Staff@5c647e05