设计模式之单例模式

匿名 (未验证) 提交于 2019-12-03 00:29:01

设计模式之单例模式(Singleton Pattern

一、概述

单例模式是最简单的设计模式之一。此设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式包含一个单一的类,该类负责创建自己的对象,同时确保该类仅有一个实例。并且提供了一个访问其对象的全局访问点,可以直接访问,不需要实例化该类的对象。

总结:

  1. 单例模式中的类只能有一个实例。
  2. 该实例只能由自己创建,不可通过外部创建。
  3. 该类必须给外部对象一个访问点

二、应用实例

1、一个党只能有一个主席。

2Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。

3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。

4、一个系统只能有一个窗口管理器或文件系统

5.、一个系统只能有一个计时工具或ID(序号)生成器

三、实现方式

1.构造函数私有化

①类外不可创建对象

②构造函数私有化的函数不能被继承

2.提供静态方法创建成员

构造函数私有化-->类外不可创建对象-->初始时类外不能调用类内非静态公有函数-->在类内创建静态函数用来创建对象

四、类图

类图说明:
instance私有静态指针变量,用于存储唯一对象的指针
Singleton()私有构造方法,用于生成对象
getInstance()公用方法,提供给用户一个接口来获得对象指针

五、实现分析

以上我们了解了单例模式的特点以及实现单例模式的思路。

然而单例模式中由于对象的初始化的时间不同产生了两种情况(懒汉与饿汉):

①懒汉:顾名思义,它很懒,如果客户不需要实例,它就不会初始化对象,只有在客户需要时调用getInstance方法生成对象。

特点:用时间换空间,对象延时生成,只在需要时才会生成的方法节省了空间

饿汉:人在饿的时候都会饥不择食,所有此种情况在类加载时就生成对象

特点:用空间换时间,在类初始化时就生成对象,占用了内存,但在调用时不需要重新生成,节省了时间。

虽然以上我们分析的比较详细了,但是在计算机中,计算机运行结果不一定如我们所料,因为计算机内部充满着并发。所以在对单例模式进行初始化操作时,如果两个线程同时调用了getInstance方法,岂不是会形成两个对象,这就与我们的初衷相违背。所以之后我们介绍线程不安全和线程安全的两种实现形式。

六、代码及说明

1.C++

①懒汉、线程不安全

Code

#include<iostream> using namespace std;  class Singleton { 	private: 		static Singleton *instance; 		Singleton() 		{ 			///////;  		} 	public: 		static Singleton *getInstance() 		{ 			if(!instance) 				instance=new Singleton(); 			return instance; 		}  }; Singleton *Singleton::instance=NULL;  int main() { 	Singleton *p=Singleton::getInstance(); 	Singleton *q=Singleton::getInstance(); 	cout<<p<<endl; 	cout<<q<<endl; }

Result:

②懒汉,线程安全(加锁)

Code

class Singleton { 	private: 		static Singleton *instance; 		Singleton() 		{ 			pthread_mutex_init(&mutex,NULL); 		} 	public: 		static pthread_mutex_t mutex; 		static Singleton *getInstance() 		{ 			pthread_mutex_lock(&mutex); 			if(!instance) 				instance=new Singleto(); 			pthread_mutex_unlock(&mutex);	 			return instance; 		}  }; pthread_mutex_t Singleton::mutex; Singleton *Singleton::instance=NULL;

③懒汉,线程安全(内部静态变量)(推荐)

Code

class Singleton{ 	private:	 		Singleton() 		{ 			///////;  		} 	public: 		static Singleton *getInstance() 		{ 			static Singleton instance; 			return &instance; 		}  };

④饿汉,线程安全(推荐)

Code
class Singleton { 	private: 		static Singleton *instance; 		Singleton() 		{ 			///////;  		} 	public: 		static Singleton *getInstance() 		{ 			return instance; 		}  }; Singleton *Singleton::instance=new Singleton(); 

2.JAVA

①懒汉,线程不安全

Code

public class Singleton { 	private static Singleton instance; 	private Singleton() 	{ 		///////; 	} 	public static Singleton getInstance() 	{ 		if(instance==null) 		{ 			instance=new Singleton(); 		} 		return instance; 	} 	 	 	public static void main(String args[]) 	{ 		Singleton p=Singleton.getInstance(); 		Singleton q=Singleton.getInstance(); 		 		System.out.println(p); 		System.out.println(q); 	} } 

Result:

②懒汉,线程安全(加锁1)

但每次调用方法都会产生同步,所以性能不好

public class Singleton { 	private static Singleton instance; 	private Singleton() 	{ 		///////; 	} 	public static synchronized Singleton getInstance() 	{ 		if(instance==null) 		{ 			instance=new Singleton(); 		} 		return instance; 	} } 

③懒汉,线程安全(加锁2,②的改进版

只有第一次调用方法时,才进行同步,但是可能多线程同时第一次调用,都通过第一次判空,所以在同步时,应该再次进行判空。

public class Singleton { 	private static Singleton instance; 	private Singleton() 	{ 		///////; 	} 	public static Singleton getInstance() 	{ 		if(instance==null) 		{ 			synchronized(Singleton.class) 			{ 				if(instance==null) 					instance=new Singleton(); 			} 		} 		return instance; 	} }

懒汉,线程安全(静态内部类)(推荐)

该方法利用了classloader的机制来保证初始化instance时只有一个线程,所以也是线程安全的,同时没有性能损耗

public class Singleton { 	private Singleton() 	{ 		///////; 	} 	private static class LazyHolder 	{ 		private static final Singleton instance=new Singleton(); 	} 	public static Singleton getInstance() 	{ 		return LazyHolder.instance; 	} } 

饿汉,线程安全(推荐)

public class Singleton { 	private static Singleton instance=new Singleton(); 	private Singleton() 	{ 		///////; 	} 	public static Singleton getInstance() 	{ 		return instance; 	} } 

六、优缺点

1.优点

①实例控制

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。

②灵活性

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

2.缺点

①开销

饿汉方式每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。

②可能的开发混淆

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

③对象生存期

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

本章为所有设计模式的第一章,在进行编写的时候查阅了很多资料并且学到了很多,希望和大家一起分享。

如果在编写的时候出现了错误(尤其是代码部分)还希望大家积极指正。也希望有独特见解的朋友能够不吝赐教,与君共勉。




标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!