(2.2.2.2)设计模式--单例模式(二)登记式
2015-09-15 09:03
302 查看
<span style="font-family: 'Microsoft YaHei'; font-size: 18px;">本文是设计模式学习笔记的第二篇文章,主要分析的是单例模式。包括懒汉式,饿汉式,登记式,以及懒汉式的改进型, 还有一个关于读取propertoes配置文件的实例。现在看来要写四节了。这是第二节,上一节分析了最基本的懒汉式和饿汉式, 这次我们来看一下登记式。 </span>
登记式实际对一组单例模式进行的维护,主要是在数量上的扩展,通过map我们把单例存进去,这样在调用时,先判断该单例是否已经创建,是的话直接返回,不是的话创建一个登记到map中,再返回。对于数量又分为固定数量和不固定数量的。下面采用的是不固定数量的方式,在getInstance方法中加上参数(string name)。然后通过子类继承,重写这个方法将name传进去。让我们看看代码吧。
首先是父类:
[java] view
plaincopyprint?
//采用Map配置多个单例
public class MySingleton3 {
// 设立静态变量,直接创建实例
private static Map<String, MySingleton3> map = new HashMap<String, MySingleton3>();
// -----受保护的-----构造函数,不能是私有的,但是这样子类可以直接访问构造方法了
//解决方式是把你的单例类放到一个外在的包中,以便在其它包中的类(包括缺省的包)无法实例化一个单例类。
protected MySingleton3() {
System.out.println("-->私有化构造函数被调用,创建实例中");
}
// 开放一个公有方法,判断是否已经存在实例,有返回,没有新建一个在返回
public static MySingleton3 getInstance(String name) {
if (name == null) {
name = MySingleton3.class.getName();
System.out.println("-->name不存在,name赋值等于"+MySingleton3.class.getName());
}
if (map.get(name) == null) {
try {
System.out.println("-->name对应的值不存在,开始创建");
map.put(name, (MySingleton3)Class.forName(name).newInstance());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}else {
System.out.println("-->name对应的值存在");
}
System.out.println("-->返回name对应的值");
return map.get(name);
}
public Map<String, MySingleton3> getMap(){
return map;
}
}
然后写了俩个子类:
[java] view
plaincopyprint?
public class MySingleton3Childa extends MySingleton3 {
public static MySingleton3Childa getInstance() {
return (MySingleton3Childa) MySingleton3Childa
.getInstance("com.xq.mysingleton.MySingleton3Childa");
}
//随便写一个测试的方法
public String about() {
return "---->我是MySingleton3的第一个子类MySingleton3Childa";
}
}
[java] view
plaincopyprint?
public class MySingleton3Childb extends MySingleton3 {
static public MySingleton3Childb getInstance() {
return (MySingleton3Childb) MySingleton3Childb
.getInstance("com.xq.mysingleton.MySingleton3Childb");
}
//随便写一个测试的方法
public String about() {
return "---->我是MySingleton3的第二个子类MySingleton3Childb";
}
}
然后是客户端代码,这回测试用例比较多哈:
[java] view
plaincopyprint?
/**
* 登记式单例模式
* MySingleton2
*/
public static void myprint3(){
System.out.println("-----------------登记式单例模式----------------");
System.out.println("第一次取得实例(登记式)");
MySingleton3 s1 = MySingleton3.getInstance(null);
System.out.println(s1);
System.out.println("第二次取得实例(登记式)");
MySingleton3Childa s3 = MySingleton3Childa.getInstance();
System.out.println(s3);
System.out.println(s3.about());
System.out.println("第三次取得实例(登记式)");
MySingleton3Childb s4 = MySingleton3Childb.getInstance();
System.out.println(s4);
System.out.println(s4.about());
System.out.println("第四次取得实例(非正常直接new子类的构造方法)");
MySingleton3Childb s5 = new MySingleton3Childb();
System.out.println(s5);
System.out.println(s5.about());
System.out.println("输出父类中Map保存的所有单例,可以看出,直接new出来的实例并没有存在Map中");
System.out.println(s1.getMap());
System.out.println();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
//懒汉式
//myprint();
//饿汉式
//myprint2();
//懒汉式改进
//myprint2a();
//登记式
myprint3();
}
先让我们看下输出结果:
-----------------登记式单例模式----------------
第一次取得实例(登记式)
-->name不存在,name赋值等于com.xq.mysingleton.MySingleton3
-->name对应的值不存在,开始创建
-->私有化构造函数被调用,创建实例中
-->返回name对应的值
com.xq.mysingleton.MySingleton3@6e1408
第二次取得实例(登记式)
-->name对应的值不存在,开始创建
-->私有化构造函数被调用,创建实例中
-->返回name对应的值
com.xq.mysingleton.MySingleton3Childa@f62373
---->我是MySingleton3的第一个子类MySingleton3Childa
第三次取得实例(登记式)
-->name对应的值不存在,开始创建
-->私有化构造函数被调用,创建实例中
-->返回name对应的值
com.xq.mysingleton.MySingleton3Childb@1f33675
---->我是MySingleton3的第二个子类MySingleton3Childb
第四次取得实例(非正常直接new子类的构造方法)
-->私有化构造函数被调用,创建实例中
com.xq.mysingleton.MySingleton3Childb@7c6768
---->我是MySingleton3的第二个子类MySingleton3Childb
输出父类中Map保存的所有单例,可以看出,直接new出来的实例并没有存在Map中
{com.xq.mysingleton.MySingleton3Childa=com.xq.mysingleton.MySingleton3Childa@f62373, com.xq.mysingleton.MySingleton3Childb=com.xq.mysingleton.MySingleton3Childb@1f33675, com.xq.mysingleton.MySingleton3=com.xq.mysingleton.MySingleton3@6e1408}
有点乱哈,让我们分析下。
先后总共我们创建创建了4个单例。
第一种情况是我们直接调用父类的方法,传入空值,结果调用父类的方法创建一个实例,并且登记在map中,后期打印可知为
com.xq.mysingleton.MySingleton3=com.xq.mysingleton.MySingleton3@6e1408
第二种情况是我们调用子类a的方法,由a创建一个实例并且登录在父类的map中。后期打印可知为
com.xq.mysingleton.MySingleton3Childa=com.xq.mysingleton.MySingleton3Childa@f62373
第三种情况是我们调用子类b的方法,由a创建一个实例并且登录在父类的map中。后期打印可知为
com.xq.mysingleton.MySingleton3Childb=com.xq.mysingleton.MySingleton3Childb@1f33675
第四种情况是我们直接调用子类b的构造函数,如上虽然我们创建了一个实例com.xq.mysingleton.MySingleton3Childb@7c6768,但是并没有存在map中。
其实这也是这个解决方案的缺点,因为我们将父类构造方法对外公开了(protected)。。。。有一个解决方法是把你的单例类放到一个外在的包中,以便在其它包中的类(包括缺省的包)无法实例化一个单例类。
相关文章推荐
- HTTP协议报文、工作原理及Java中的HTTP通信技术详解
- java学习之System类
- iOS 警告收录及科学快速的消除方法---来源董铂然
- Node.js timer的优化故事
- 关于ExpandableListView用法的一个简单小例子
- hdu 5442 Favorite Donut (最大表示法+KMP)
- PHP于Post和Get得到的数据写入到文件中
- PowerShell时间记录脚本
- android之ViewFlipper实现左右滑动动画效果
- 近一年来做的动效设计整理
- 杨辉三角求二项式分布
- EventBus 页面传值并启动Activity
- GridView实时更新数据
- 讲解Java中如何构造内部类对象以及访问对象
- 图片变形的抗锯齿处理方法
- (2.2.2.1)设计模式--单例模式(一)懒汉式和饿汉式
- IOS学习笔记 ---- 15/09/14
- [刷题]Best Time to Buy and Sell Stock Show result
- C语言接续符和转义符
- Jump Game 的三种思路 - leetcode 55. Jump Game