单例模式是最基础的模式,记得上学的时候,老师介绍的也就是单例,工厂的简单应用。
今天学到了一个新的知识点,往常概念里为了保证是单例,必须要构造函数设置为private,这样才能保证在其他地方不被实例化出对象。可是private的类不能被继承,这点从来没考虑到。
举3个例子看看代码,基本就能明白基础的单例模式的意义。
public class Singleton { //在自己内部定义自己一个实例 //注意这是private 只供内部调用 private static Singleton instance = new Singleton(); //如上面所述,将构造函数设置为私有 private Singleton(){ } //静态工厂方法,提供了一个供外部访问得到对象的静态方法 public static Singleton getInstance() { return instance; } }
下面这种方式被称为懒汉式:P public class Singleton { //和上面有什么不同? private static Singleton instance = null; //设置为私有的构造函数 private Singleton(){ } //静态工厂方法 public static synchronized Singleton getInstance() { //这个方法比上面有所改进 if (instance==null) instance=new Singleton(); return instance; } }
以上两种实现方式均失去了多态性,不允许被继承。还有另外一种灵活点的实现,将构造函数设置为受保护的,这样允许被继承产生子类。这种方式在具体实现上又有所不同,可以将父类中获得对象的静态方法放到子类中再实现;也可以在父类的静态方法中进行条件判断来决定获得哪一个对象;在GOF 中认为最好的一种方式是维护一张存有对象和对应名称的注册表(可以使用HashMap 来实现)。下面的实现参考《java 与模式》采用带有注册表的方式
public class Singleton { //用来存放对应关系 private static HashMap sinRegistry = new HashMap(); static private Singleton s = new Singleton(); //受保护的构造函数 protected Singleton() {} public static Singleton getInstance(String name) { if(name == null) name = "Singleton"; if(sinRegistry.get(name)==null) { try{ sinRegistry.put(name , Class.forName(name).newInstance()); }catch(Exception e) { e.printStackTrace(); } } return (Singleton)(sinRegistry.get(name)); } public void test() { System.out.println("getclasssuccess!"); } } public class SingletonChild1 extends Singleton { public SingletonChild1(){} static public SingletonChild1 getInstance() { return (SingletonChild1)Singleton.getInstance("SingletonChild1"); } public void test() { System.out.println("getclasssuccess111!"); } }