- 单例模式概念:Ensure a class has only one instance,and provide a global point of access to it.即是确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的通用代码:
package singleton;
/**
*@author xpengfei
*@creat 8:04:31 PM Oct 9, 2017
*单例模式的通用代码
*饿汉式单例
*/
public class Singleton {
//自行实例化一个对象
private static final Singleton singleton=new Singleton();
//限制产生多个对象
private Singleton(){}
//编写get方法获取实例对象
public static Singleton getSingleton(){
return singleton;
}
//类中的其他static方法
public static void dosomething(){}
}
2.示例:
皇帝类设置为单例模式,则产生的对象只有一个。
package singleton;
/**
*@author xpengfei
*@creat 7:51:53 PM Oct 9, 2017
*皇帝类,单例类
*/
public class Emperor {
//初始化一个对象
private static final Emperor emperor=new Emperor();
//将该类的构造函数设置为私有,不允许外部类调用构造函数创建对象
private Emperor(){}
//静态方法获取该类的对象
public static Emperor getInstance(){
return emperor;
}
//静态方法
public static void say(){
System.out.println("aaaaaaaaa");
}
}
臣子类中三次循环所获取的皇帝对象是同一个对象
package singleton;
/**
*@author xpengfei
*@creat 7:52:05 PM Oct 9, 2017
*/
public class Minister {
public static void main(String[] args) {
for(int i=0;i<3;i++){
Emperor e=Emperor.getInstance();
e.say();
}
}
}
3.单例模式的优点:
- 由于单例模式中只有一个对象,所以减少了内存开支,特别是一个对象需要频繁的创建、销毁的时候,而且对象的创建或销毁的时候性能又无法进行优化。
- 减少了系统的性能开销,当一个对象的产生需要比较多的资源的时候,例如:读取配置、产生其它依赖对象时,可以通过单例模式用永久驻留内存的方式解决(JavaEE中采用单例模式需要注意JVM垃圾回收机制)。
- 单例模式可以避免对资源的多重占用,例如:一个写文件动作,由于只有一个实例在内存中,避免了对同一个资源文件的同时写操作。
- 单例模式可以在系统设置全局的访问点,优化和共享资源访问。例如:可以设计一个单例类,负责所有数据表的映射处理。
4.单例模式的缺点:
- 单例模式一般没有接口,扩展很难,想要扩展的话只有修改代码。
- 单例模式对测试不利。在并发环境中,如果单利模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。
- 单例模式与单一职责原则有冲突。
5.单例模式使用场景:
- 要求生成唯一序列号的环境。
- 在整个项目中需要一个共享访问点或共享数据,例如:web页面上的计数器,可以不用每次都把刷新的记录放到数据库中,使用单例模式保持计数器的值,并确保是线程安全的。
- 创建一个对象需要消耗的资源过多,例如:访问IO和数据库等资源。
- 需要定义大量的静态常量和静态方法的方法(如工具类),可以采用单例模式(也可以直接声明为static方法)。
6.懒汉式单例:
package singleton;
/**
*@author xpengfei
*@creat 8:04:31 PM Oct 9, 2017
*懒汉式单例
*/
public class Singleton {
//自行实例化一个对象
private static Singleton singleton=null;
//限制产生多个对象
private Singleton(){}
//编写get方法获取实例对象
public static synchronized Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
//类中的其他static方法
public static void dosomething(){}
}
7.单例模式的扩展:
可以将单例模式扩展为产生实例数量有限的形式:
Emperor类中设置了最多能产生的实例的个数:
package singleton;
import java.util.ArrayList;
import java.util.Random;
/**
*@author xpengfei
*@creat 7:51:53 PM Oct 9, 2017
*皇帝类,单例类
*/
public class Emperor {
//定义最多能产生的实例数量
private static int maxNumOfEmperor=5;
//每一个对象都有名字,使用list存储
private static ArrayList<String>namelist=new ArrayList<>();
//定义一个列表存储所有的实例对象
private static ArrayList<Emperor>emperorlist=new ArrayList<>();
//当前对象序列号
private static int countNumOfEmperor=0;
//产生所有的对象
static {
for (int i = 0; i < maxNumOfEmperor; i++) {
emperorlist.add(new Emperor("第"+(i+1)+"个皇帝"));
}
}
//将该类的构造函数设置为私有,不允许外部类调用构造函数创建对象
private Emperor(String name){
namelist.add(name);
}
//静态方法获取该类的对象
public static Emperor getInstance(){
Random random=new Random();
//随机取出一个皇帝对象
countNumOfEmperor=random.nextInt(maxNumOfEmperor);
return emperorlist.get(countNumOfEmperor);
}
//静态方法
public static void say(){
System.out.println(namelist.get(countNumOfEmperor));
}
}
Minister类中随机访问
package singleton;
/**
*@author xpengfei
*@creat 7:52:05 PM Oct 9, 2017
*/
public class Minister {
public static void main(String[] args) {
for(int i=0;i<10;i++){
Emperor e=Emperor.getInstance();
System.out.print("第"+(i+1)+"个大臣参拜的是:");
e.say();
}
}
}
结果如下: