设计模式-单例模式

在现实生活中,总有些事物有且只有一个对象的,例如皇帝,名家的真迹。

对于这类事物在设计类的时候就要考虑到,这种类只能生成一个对象,如果生成了多个对象就与现实世界的规律不符了。

我们应该如何来控制单例的设计:

(1)首先我们不能把让用户想使用其他类一样去直接使用new 调用类的构造方法,不能让用户调用构造方法,即将构造方法设置为私有属性,这样用户就不能用new关键字实例化对象了,与此同时在类中必须要设置一个可以返回类对象实例的方法,否则将会无法实现类的实例化。

(2)要考虑到拷贝构造函数,在java中类要实现Cloneable接口还可以完成拷贝,只要不实现Cloneable方法即可。但在c++却不同,c++中要把拷贝构造函数设置为私有。

(3)考虑线程安全问题

(4)可以通过反射机制实现单例,具体请参看http://blog.csdn.net/nifenggege8888/article/details/40827249,工厂方法模式的第三种扩展

下面看一个线程安的例子:

首先定义一个皇帝类,代码如下:

package com.feng.singleton;

public class Emperor {

	//初始化一个皇帝,让用户都是用这一个皇帝实例
	private static final Emperor emperor = new Emperor();
	
	private Emperor()
	{
		//皇帝只应该有一个,这就是一个单例,构造方法设置为private
	}
	
	//提供一个返回实例对象的方法
	public static Emperor getInstance()
	{
		return emperor;
	}
	
	//皇帝有一个说话的方法,最好是static
	public static void say()
	{
		System.out.println("皇帝开始说话了。。。。。");
	}
		
}
接着定义一个大臣类,大臣每天来朝拜皇帝,朝拜的都是同一个人

package com.feng.singleton;

public class Minister {

	public static void main(String[] args)
	{
		//大臣三天都朝拜一个皇帝,虽然多次获取对象,但都是同一个对象
		for(int day=0; day<3; day++)
		{
			Emperor emperor = Emperor.getInstance();
			emperor.say();
		}
	}
}
我们稍对皇帝类进行一下改造

package com.feng.singleton;

public class Emperor {

	//初始化一个皇帝,让用户都是用这一个皇帝实例
	private static Emperor emperor = null;
	
	private Emperor()
	{
		//皇帝只应该有一个,这就是一个单例,构造方法设置为private
	}
	
	//提供一个返回实例对象的方法
	public static Emperor getInstance()
	{
		if(null == emperor)
		{
			emperor = new Emperor();
		}
		return emperor;
	}
	
	//皇帝有一个说话的方法,最好是static
	public static void say()
	{
		System.out.println("皇帝开始说话了。。。。。");
	}
		
}
在上面的代码中,如果实在单线程中运行时没有问题的,如果是在多线程中,就有可能会创建出多个对象出来,例如,第一个线程A运行到if(null == emperor),一开始emperor是为空,在走emperor = new Emperor();这条语句之前,另一个线程B运行到了if(null == emperor);这条语句,此时线程A还没有创建Emperor对象,所以线程B也会走到emperor = new Emperor(); 这样的话线程A,B都会建造出一个Emperor对象出来,这就和单例相违背了。所以这种写法是线程不安全的例子。

解决线程不安全问题的方法有很多:

(1)在getInstance()方法前加上synchronized关键字

(2)也可以在geInstance()方法里面加上synchronized来实现(都是使用线程同步机制来解决)

(3)使用本贴中实现的线程安全代码(简单,实用)

单例模式的优点:

(1)单例模式在内存中只有一个对象,节省内存,减少系统的开销

(2)可以避免对资源的多重占用

(3)可以在系统中设置全局访问点,优化和共享资源访问

单例模式的缺点:
(1)单例模式一般没有借口,扩展困难。一般只要扩展就要修改代码。接口对单例模式没有意义,因为单例模式就是自己实现实例化。

(2)单例模式对测试不利。如果单例模式没有完成,其他模块是没法测试的。

(3)单例模式与单一职责原则冲突

单例模式的使用场景:

(1)要求生成唯一序列号的坏境

(2)在整个项目中需要一个共享访问点或共享数据

(3)创建一个对象需要消耗资源过多时。

(4)需要定义大量的静态常量和静态方法的环境

关于c++实现的单例模式,请参考另一篇文章:

http://blog.csdn.net/nifenggege8888/article/details/25425859

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值