三、创建型模式:单例模式(SINGLETON)

        俺有6个漂亮的老婆,她们的老公都是我,我就是我们家里的老公Singleton,她们只要说道“老公”,都是指的同一个人,那就是我(刚才做了个梦啦,哪有这么好的事)



定义  

        有单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。




使用场景


        当类只能有一个实例而且第三方可以从一个公共的访问点访问它时。

        当一个唯一的实例可以通过子类化来扩展,而且第三方需要在不更改代码的情况下就能使用一个扩展的实例时。

        


优缺点分析

优点:

1.实例控制        

        对唯一的实例做出访问控制。

        允许改变实例的数目,事实上单例模式只是实例有限的类的一种特列,通过计数等方式可以做到双例模式,三例模式等需要实例化有限次的类。

2.灵活性

        因为类控制了实例化过程,所以类可以灵活更改实例化过程。

缺点:

1.开销

       虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。

2.可能的开发混淆

       使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。

3.对象生存期

       不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用。



单例模式UML图




应用场景及代码分析

        在开头的时候提到梦中的时候梦到了自己有好多的老婆,有中国的老婆、有美国的老婆…(ps:在我们伟大的天朝里,可是施行一夫一妻、男女平等的婚姻制度)。为了给大家演示单例模式,我们假设有2个老婆,一个中国的老婆、一个美国的老婆,老公只有一个,老公要时常的陪妻子约会,妻子觉得单独和老公出去才是浪漫,所以她们都想老公只带自己出去约会。

       首先我们先看一下老公的类,因为老公只有一个,所以老公我们使用单例模式创建,如下代码:


//单例,老公类
public class Husband {

	//老公只有一个
	private static Husband instance;

	private Husband() {
	}

	public static Husband getInstance() {
		if (instance == null) {
			instance = new Husband();
		}
		return instance;
	}

	public void show(){
		System.out.println("老公可是一个安静的美男子!");
	}
	
	public void date(){
		System.out.println("美男子可以和亲爱的妻子约会了!");
	}
}


两个老婆分别有找老公和约会的方法

//中国妻子类
public class ChinaWife {
	
	private Husband myHusband = null;
	
	//找老公
	public void showHusband(){
		myHusband = Husband.getInstance();
		myHusband.show();
	}

	//和老公约会
	public void dateWithHusband(){
		myHusband = Husband.getInstance();
		myHusband.date();
	}
}

//美国妻子
public class AmericanWife {

	private Husband myHusband = null;
	
	//找老公
	public void showHusband(){
		myHusband = Husband.getInstance();
		myHusband.show();
	}

	//和老公约会
	public void dateWithHusband(){
		myHusband = Husband.getInstance();
		myHusband.date();
	}
}

实现了老公和妻子的代码以后,我们要开始测试了:

public class SingletonTest {
	
	public static void main(String[] args){
		AmericanWife amWife = new AmericanWife();
		System.out.println("美国妻子:我要找老公!");
		amWife.showHusband();
		System.out.println("美国妻子:老公和我约会吧!");
		amWife.dateWithHusband();
		
		ChinaWife chWife = new ChinaWife();
		System.out.println("中国妻子:我要找老公!");
		chWife.showHusband();
		System.out.println("中国妻子:老公和我约会吧!");
		chWife.dateWithHusband();
	}
}

结果如下:

美国妻子:我要找老公!

老公可是一个安静的美男子!

美国妻子:老公和我约会吧!

美男子可以和亲爱的妻子约会了!

中国妻子:我要找老公!

老公可是一个安静的美男子!

中国妻子:老公和我约会吧!

美男子可以和亲爱的妻子约会了!



        我们可以看到当两个妻子都能找到老公,老公是同一个人,而且都和老公约会了。

        有一天,美国老婆希望老公和她出去约会,他心情愉悦,可是在他准备好好打扮自己的时候,中国妻子开开心心的跑了过来,“老公,和奴家约会去呗!”,这可怎么办啊,老公可没有韦小宝那么机灵,答应了美国老婆,可又不想让中国老婆失望,他陷入了思考之中!

        在我们的老公的实例创建方法中,

if (instance == null) {

instance = new Husband();

}

        美国老婆申请了老公实例,这时候老公实例还没有创建,所以instance ==null,那么老公会创建出一个实例来,可是还没等老公创建出实例,中国老婆也过来申请老公了,这时候老公还是没有创建出来,所以instance还是null,老公还会创建出来,这样就创建出了2个老公实例,可老公明明就是1个啊。在我们的代码中,如果有多个线程同时访问老公创建实例的方法,就不满足我们单例模式的单例了。

我们需要为实例过程加锁,修改老公类:


//单例,老公类
public class Husband {

	static Lock lock = new ReentrantLock();

	// 老公只有一个
	private static Husband instance;

	private Husband() {
	}

	public static Husband getInstance() {
		//这里判断是为了防止频繁的进行加解锁
		if (instance == null) {
			//加上锁
			lock.lock();
			//创建实例,并且能够防止多次创建实例
			if (instance == null) {
				instance = new Husband();
			}
			//解锁
			lock.unlock();
		}
		return instance;
	}

	public void show() {
		System.out.println("老公可是一个安静的美男子!");
	}

	public void date() {
		System.out.println("美男子可以和亲爱的妻子约会了!");
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值