单例模式(Singleton Pattern)的使用
单例模式
是最简单的设计模式之一
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
一、单例模式优点
单例模式主要是为了避免因为创建了多个实例造成资源的浪费,且多个实例由于多次调用容易导致结果出现错误,而使用单例模式能够保证整个应用中有且只有一个实例
即保证类在内存中只有一个对象,减少了内存开销;
注意!!:
1、单例类 只能有一个 实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例,且 用类名. 调用。
二、单例模式应用场景
- 资源管理器,资源对象数据的加载和卸载(无状态不需要实例化的对象);
- 生命周期在游戏中永不消毁的对象
- 单一客户端连接服务器等;
三,单例模式的设计思想(复习时选看)
(1)不允许其他程序用new对象。
因为new就是开辟新的空间,在这里更改数据只是更改的所创建的对象的数据,如果可以new的话,每一次new都产生一个对象,这样肯定保证不了对象的唯一性。
(2)在该类中创建对象
因为不允许其他程序new对象,所以这里的对象需要在本类中new出来
(3)对外提供一个可以让其他程序获取该对象的方法
因为对象是在本类中创建的,所以需要提供一个方法让其它的类获取这个对象。
四,单例模式的使用
unity继承monobehavior的单例
只需要在Awake()里面,添加一句instance = this;
注意在Unity中不要使用new
来创建MonoBehaviour实例
public class test : MonoBehaviour
{
private static test instance;//1. static!!
void Awake ()
{
instance = this;
}
public static test GetInstance()
{
return instance;
}
}
使用方式
test2.GetInstance().方法/属性/等 ;
unity中范型写法(可不用双重锁)
public class A<T> where T : new()//确保无参
{
private static T instance;
public static T GetInstance()
{
if (instance == null)
{
instance = new T();
}
return instance;
}
}
public class B : A<B>
{
}
C#版本的 普通类单例。
一饿汉模式(常用)
public class Singleton
{
// 自行预先实例化,内部定义自己唯一实例,只供内部使用 //
private readonly static Singleton Instance = new Singleton();
private Singleton()
{
// Do Something
}
// 提供外部访问的静态方法,来对内部唯一实例进行访问 //
public static Singleton GetInstance()
{
return Instance;
}
}
二 懒汉模式[线程不安全,不可用]
public class Singleton {
//1 private satic
private static Singleton instance = null;
//2 提供私有构造函数;这样该类就不会被其他类实例化
private Singleton(){}
//3 获取唯一可用的对象
public static Singleton GetInstance()
{
if (instance == null )
instance = new Singleton();
return instance;//返回唯一实例,以便外部调用
}
}
使用方式
Singleton.GetInstance().方法/属性/等 ;
- 两者比较:
- 所谓饿汉式,就是直接创建出类的实例化;
而对于懒汉式,就是在需要的时候再创建类的实例化
- 饿汉式:简单来说就是空间换时间,因为上来就实例化一个对象,占用了内存,(也不管你用还是不用)(但是这个浪费可以忽略,所以这种方式也是推荐使用的)。
懒汉式:简单的来说就是时间换空间,与饿汉式正好相反
- 饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
以下解释引用
public static Singleton GetInstance()
{
//判断singleton是否为null,如果为null,即判定需要实例化
if (singleton == null)
{ //
singleton = new Singleton();
}
return singleton;
}
比如,现在有A线程和B线程,A线程刚好在这个GetInstance()方法中,刚刚判断完非空(此时为null),即需要创建实例,然而,就是这么巧,B线程抢到了CPU的执行权,A线程sleep了,这时,B线程也进行了这个判断,和A一样,都需要创建实例,而这时,A也抢到了CPU,这时,B就sleep了,然后A执行了实例化后,B又抢到CPU执行权,然后B也实例化,这时,出现问题了,A和B都实例化了一个对象,这就是赤果果的两个对象呀,单例呢,唯一呢,全都没了(这将导致第一个实例化的数据丢失)。
三 双重校验锁模式的懒汉式【线程安全的】
using System.Threading;//留意
public class Singleton {
/**
* 懒汉式变种,属于懒汉式中最好的写法,保证了:延迟加载和线程安全
*/
private static Singleton instance=null;
private Singleton() {};
public static Singleton GetInstance()
{
if (instance == null) //进行了两次null检查
{
synchronized (Singleton.class)
{ //synchronized之一,在方法定义时使用,多线程状态下,这个方法只能同时被同一个线程执行;
//可换用lock
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
访问方式
Singleton instance = Singleton.GetInstance();//获得引用
四枚举[推荐使用,但无法继承]
public enum SingletonEnum
{
instance;
private SingletonEnum() {}
public void method(){
}
}
访问方式
SingletonEnum.instance.method();
五 泛型(结合双重锁)
在一个案例中,我们可能需要使用到不止一个单例模式类,甚至更多。那么此时,使用泛型单例模式模板来实现单例模式,我们可以有两种不同的方法来实现它:
4.3.1 首先我们来看下泛型模板,我们对泛型类进行约束,T只能是一个Class,并且有一个公共无参构造函数,代码如下:
class Singleton<T> where T: class,new()
{
private static T instance;
private static readonly object syslock=new object();
public static T GetInstance()
{
if (instance == null)
{
lock (syslock) {
if (instance == null)
{
instance = new T();
}
}
}
return instance;
}
}
class B : Singleton<B> {
public void ss() {
Console.WriteLine("111");
}
}
萌新一枚,咳咳,不是食物链顶端的那种萌新,若有误,望指正