[DesignPattern] 设计之禅读书笔记(二) 单例模式
-
单例模式(Singleton Pattern)
- Ensure a class has only one instance, and provide a global point of access to it.(确保只有一个实例, 而且自行实例化并向整个系统提供这个实例。)
- 模板
- 通用代码
public class Singleton { private static final Singleton singleton = new Singleton(); private Singleton(){} //限制多个对象产生 //通过该方法获得实例化对象 public static Singleton getInstance(){ return singleton; } //类中的其他方法,尽量时static public static void doSomething() { } }
-
单例模式的优点
- 节省内存开支
- 避免资源多重占用
- 在系统设置全局的访问点,优化和共享资源
-
单例模式的缺点
- 单例模式一般没有接口, 扩展很困难, 若要扩展,除了修改代码基本上没有第二种途径可以实现
- 单例模式对测试时不利的
- 单例模式与单一职责原则有冲突
-
单例模式的使用场景
- 要求生成唯一序列号的环境
- 在整个项目中需要共享访问点和共享数据,如web计数器,并确保线程安全
- 创建一个对象需要消耗的资源过多,eg. IO和数据库
- 需要定义大量静态常量方法(如工具类)的环境, 可以采用单例模式。
-
单例模式考虑问题
- 懒汉模式的时候的线程安全问题, 尽量使用饿汉模式
- 需要考虑对象的复制,解决方法是不提供Cloneable接口
-
单例的扩展
- 产生有限个对象 加入数量限制变量
- 例子
package shejizhichan.singleton; import java.util.Random; import java.util.Vector; public class Emperor { public static final int maxMumOfEmperor = 2; private static Vector
names = new Vector<>(); private static Vector emperors = new Vector<>(); private static int currentEmperor = 0; static { for (int i = 0; i < maxMumOfEmperor; i++) { emperors.add(new Emperor("Emperor= " + (i + 1))); } } private Emperor(){} private Emperor(String name){ names.add(name); } public static Emperor getInstance() { Random random = new Random(); currentEmperor = random.nextInt(maxMumOfEmperor); return emperors.get(currentEmperor); } public static void say() { System.out.println(names.get(currentEmperor)); } } package shejizhichan.singleton; public class Minister { public static void main(String[] args) { int ministerNum = 5; for (int i = 0; i < ministerNum; i++) { Emperor emperor = Emperor.getInstance(); System.out.print("No." + (i+1) + " Minister see "); emperor.say(); } } } -
最佳实践
- 单例是比较简单的模式, 在Spring中, 每个Bean默认都是单例, 这样Spring容易就可以管理Bean的生命期。如果采用非单例(Prototype), 则Bean初始化后管理较给J2EE容器。