设计模式(java) 单例模式 单例类
·单例类
单实例类,就是这个类只能创建一个对象,保证了对象实例的唯一性。
1.单例模式( Singleton Pattern) 是一个比较简单的模式, 其定义如下:
Ensure a class has only one instance, and provide a global point of access to it.( 确保某一个类
只有一个实例, 而且自行实例化并向整个系统提供这个实例。 )
1.1单例模式通用代码
public class Singleton { private static final Singleton singleton = new Singleton(); //限制产生多个对象 private Singleton(){ }
//通过该方法获得实例对象 public static Singleton getSingleton(){ return singleton; }
//类中其他方法, 尽量是static public static void doSomething(){ } }
2.单例模式实例
/*静态方法是属于类的,内存必须为它分配内存空间,这个空间一直由静态方法占用, * 内存管理器不会由于静态方法没有被调用而将静态方法的存储空间收回, * 这样如果将所有的方法都声明为静态方法,就会占用大量的内存空间,最后是系统变慢。 * 而普通的成员方法是由对象调用的,内存并不会一直为其分配内存,只有调用的时候才为其分配存储空间, * 而当其没有被调用时,存储空间就会被内存管理其收回, 释放没有用的空间,提高的系统的运行速率!*/ class Singleton { private static Singleton instance; //使用static修饰,因为它要在该类的静态方法(getInstance)中被访问,作用是一个引用变量指向对象。 private Singleton(){}; //提供一个私有访问权限的构造方法,禁止外部创建对象,限制产生多个对象。 //方法必须是public的和static的,因为方法要公开被类SingletonTest调用并且 s1引用变量获取方法的方式是通过类.方法来实现的。<br> // 类的构造方法是私有的,所以外部类无法创建对象,所以用类.方法得到对象,这样就约束了创建对象的个数。 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); //自行实例化(在Singleton中自己使用new Singleton()) } return instance; } // 类中其他方法,尽量是static public static void say(){ System.out.println("我是独一无二的"); } } public class SingletonTest { public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); s1.say(); s2.say(); System.out.println(s1 == s2); //结果为true,这里可以看出确实是同一个对象 "=="比较两个对象的内存地址是否相同。 } }
大臣与皇帝,大臣每天拜访皇帝一次:
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("我就是皇帝某某"); } } public class Minister { @SuppressWarnings("static-access") public static void main (String[] args){ for(int day=0; day<3;day++){ Emperor emperor = Emperor.getInstance(); System.out.println("第"+(day+1)+"天"); emperor.say(); } } }
特殊情况
升级版 固定数量的皇帝类 public class Emperor{ //定义最多能产生的实例的数量 private static int maxNumOfEmperor = 2; // 每个皇帝都有名字, 使用一个ArrayList来容纳,每个对象的私有属性(如名字) private static ArrayList<String> nameList = new ArrayList<String>(); // 定义一个列表,容纳所有的皇帝实例。 private static ArrayList<Emperor> emperorList = new ArrayList<Emperor>(); //当前皇帝序列号 private static int countNumOfEmperor = 0; // private static Emperor emperor= //产生所有的对象 //static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法 static{ for (int i = 0; i < maxNumOfEmperor; i++) { //调用构造方法,构造一个皇帝对象,并把皇帝对象保存到emperorList中, emperorList.add(new Emperor("皇"+(i+1)+"帝")); } }//虽然产生了两个皇帝 ,但是使用static让然体现了“单”(一次产生两个皇帝) private Emperor() { // TODO Auto-generated constructor stub } //通过传入皇帝名称,可以构造一个皇帝对象,并把皇帝对象的属性(名称)保存到nameList中, private Emperor(String name) { // TODO Auto-generated constructor stub 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)); } }
public class Minister{ public static void main(String[] args) { //定义5个大臣 int ministerNum = 5; for (int i = 0; i < ministerNum; i++) { Emperor emperor = Emperor.getInstance(); System.out.print("第"+(i+1)+"个大臣参拜的是:"); emperor.say(); } } }
3.单例模式的特点
(1)、单例类确保自己只有一个实例。
(2)、单例类必须自己创建自己的实例。
(3)、单例类必须为其他对象提供唯一的实例。
4.1单例模式的优点
● 由于单例模式在内存中只有一个实例, 减少了内存开支, 特别是一个对象需要频繁地
创建、 销毁时, 而且创建或销毁时性能又无法优化, 单例模式的优势就非常明显。
● 由于单例模式只生成一个实例, 所以减少了系统的性能开销, 当一个对象的产生需要
比较多的资源时, 如读取配置、 产生其他依赖对象时, 则可以通过在应用启动时直接产生一
个单例对象, 然后用永久驻留内存的方式来解决( 在Java EE中采用单例模式时需要注意JVM
垃圾回收机制) 。
● 单例模式可以避免对资源的多重占用, 例如一个写文件动作, 由于只有一个实例存在
内存中, 避免对同一个资源文件的同时写操作。
● 单例模式可以在系统设置全局的访问点, 优化和共享资源访问, 例如可以设计一个单
例类, 负责所有数据表的映射处理。
4.2单例模式的缺点
● 单例模式一般没有接口, 扩展很困难, 若要扩展, 除了修改代码基本上没有第二种途
径可以实现。 单例模式为什么不能增加接口呢? 因为接口对单例模式是没有任何意义的, 它
要求“自行实例化”, 并且提供单一实例、 接口或抽象类是不可能被实例化的。 当然, 在特殊
情况下, 单例模式可以实现接口、 被继承等, 需要在系统开发中根据环境判断。
● 单例模式对测试是不利的。 在并行开发环境中, 如果单例模式没有完成, 是不能进行
测试的, 没有接口也不能使用mock的方式虚拟一个对象。
单例模式与单一职责原则有冲突。 一个类应该只实现一个逻辑, 而不关心它是否是单
例的, 是不是要单例取决于环境, 单例模式把“要单例”和业务逻辑融合在一个类中。