设计模式第六天之单例模式

这次和大家分享一下设计模式中的单例模式。

说到单例模式,我相信大家都了解,简单说就是某个类在整个程序中只有一个对象。那为什么使用单例模式呢?什么场景使用单例模式呢?

我个人认为,在程序设计中,经过分析,某个类有一个对象已经可以满足要求,如果此时再加上这个类会消耗许多资源(包括内存开销大,创建对象耗时等),这个类就推荐使用单例来实现了。比如:数据库连接及相关操作,图片加载,缓存,线程池等等。使用单例模式也可以更好的实现共享资源。

那如何实现单例模式呢?在这里我和大家分享五种方式。在这五种方式中,都是以一个简单的计算器例子来说明,计算加减乘除的类对象明显在程序中只要有一个就可以了。在这里只是为了介绍这些方式实现。

1.      饿汉模式

/**
 * 饿汉模式实现单例模式
 * 好处:简单
 * 缺点:
 * 当类加载的时候就创建了对象而不管对象时候在使用
 * 造成资源的浪费
 * 当内存不足的时候,回收了静态对象,此时访问也会带来bug
 * @author wangpeiyu
 *
 */
public class Hungry {
	private static Hungry instance= new Hungry();
	
	private Hungry(){
		
	}
	public Hungry getInstance(){
		return instance;
	}
	public int add(int a,int b){
		return a+b;
	}
	public int sub(int a,int b){
		return a-b;
	}
	public int mul(int a, int b){
		return a*b;
	}
	public float div(int a,int b)
	{
		return a/b;
	}
}

2.      懒汉模式

/**
 * 懒汉实现单例模式
 * 好处:解决了线程安全,也做到了要使用的时候才创建对象
 * 缺点:每次要获取该对象的时候,都要进行线程同步,即使在instance已经赋值了之后
 * 还要进行线程同步,这就造成了不必要的时间浪费和资源浪费
 * @author wangpeiyu
 *
 */
public class Lazy {
	private static Lazy instance=null;
	private  Lazy(){}
	public synchronized static Lazy getInstance(){
		if(instance==null){
			instance = new Lazy();
		}
		return instance;
	}
	public int add(int a,int b){
		return a+b;
	}
	public int sub(int a,int b){
		return a-b;
	}
	public int mul(int a, int b){
		return a*b;
	}
	public float div(int a,int b)
	{
		return a/b;
	}
}


3.      静态内部类方式

/**
 * 静态内部类实现单例模式
 * 好处:线程安全、也达到了延迟加载、当加载单例类的时候并没有创建对象。
 * 缺点:内存不足,回收静态对象时,在访问会出现bug
 * 无法解决发序列化导致的对象重建
 * @author wangpeiyu
 *
 */
public class StaticInClass {
	
	private StaticInClass(){
		
	}
	public static StaticInClass getInstance()
	{
		return SingletonHolder.instance;
	}
	/**
	 * 静态内部类
	 * 主要的单例类的holder
	 * @author wangpeiyu
	 *
	 */
	private static final class SingletonHolder{
		private static final StaticInClass instance = new StaticInClass();
	}
	public int add(int a,int b){
		return a+b;
	}
	public int sub(int a,int b){
		return a-b;
	}
	public int mul(int a, int b){
		return a*b;
	}
	public float div(int a,int b)
	{
		return a/b;
	}
}


4.      双重检查加锁方式

/**
 * 双重检查加锁模式实现单例模式
 * 好处:延迟了加载、线程安全,而且也避免了在instance已经赋值的情况下,多线程还要
 * 同步造成的资源浪费和无意义的等待
 * 缺点:当反序列化时无法避免会重新创建对象的问题
 * @author wangpeiyu
 *
 */
public class DCL {
	private static DCL instance = null;
	private DCL(){}
	public static DCL getInstance(){
		if(instance==null){
			synchronized (DCL.class) {
				if(instance==null)
				{
					instance = new DCL();
				}
			}
		}
		return instance;
	}
	public int add(int a,int b){
		return a+b;
	}
	public int sub(int a,int b){
		return a-b;
	}
	public int mul(int a, int b){
		return a*b;
	}
	public float div(int a,int b)
	{
		return a/b;
	}
}



5.      枚举方法

/**
 * 使用枚举实现单例
 * 好处:
 * 1.完全确保整个程序只有一个实例
 * 2.线程安全,因为枚举一旦定义结束,编译器就不允许我们再使用其构造器来创建任何实例了
 * 3.构造函数是private的,即使定义为public,一样为private
 * 4.自由序列化,这样即使在反序列化时也不会重新创建
 * @author wangpeiyu
 *
 */
public enum EnumCaculate {
	instance;
	private EnumCaculate(){
	}
	public int add(int a,int b){
		return a+b;
	}
	public int sub(int a,int b){
		return a-b;
	}
	public int mul(int a, int b){
		return a*b;
	}
	public float div(int a,int b)
	{
		return a/b;
	}
}


    在这五种实现中,我个人比较推荐枚举实现和双重检查加锁实现。原因在每个类的代码中体现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值