设计模式:设计模式 | 菜鸟教程
单例模式:创建对象单例的动作转移到另外的行为上面, 利用一个行为去创建对象自身
个人推荐:
普通脚本-->V4方案
Unity脚本-->V10方案
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
/// <summary>
/// 单例模式:创建对象单例的动作转移到另外的行为上面, 利用一个行为去创建对象自身
/// 参考文献:Implementing the Singleton Pattern in C# https://csharpindepth.com/Articles/Singleton#performance
/// 个人推荐:普通脚本-->V4方案 Unity脚本-->V8方案
/// </summary>
public class SingletonTest : MonoBehaviour
{
/// <summary>
/// 测试代码
/// </summary>
private void Start()
{
//创建第一个线程并给予委托
Thread thread1 = new Thread(new ThreadStart(thread1start));
thread1.Start();
//创建第二个线程并给予委托
Thread thread2 = new Thread(new ThreadStart(thread2start));
thread2.Start();
// 泛型单例委托
//Debug.Log(SingletonV7Test.GetInstance);
// MonoBehaviour 单例委托
//Debug.Log(SingletonTest.Instance);
}
static void thread1start()
{
Console.WriteLine("第一个线程运行");
Debug.Log(SingletonV4.Instance);
}
static void thread2start()
{
Console.WriteLine("第二个线程运行");
Debug.Log(SingletonV4.Instance);
}
private static SingletonTest instance;
public static SingletonTest Instance
{
get
{
int length = FindObjectsOfType<SingletonTest>().Length;
if (length == 0)
{
Debug.Log("单例已创建");
GameObject go = new GameObject();
go.name = typeof(SingletonTest).ToString();
instance = go.AddComponent<SingletonTest>();
return instance;
}
if (length > 1)
{
Debug.LogError("单例数量大于1");
instance = null;
return instance;
}
instance = FindObjectsOfType<SingletonTest>()[0];
Debug.Log("单例已存在");
return instance;
}
}
}
public sealed class SingletonV7Test : SingletonV7<SingletonV7Test>
{
}
// 第一个版本 ——不是线程安全的
public sealed class SingletonV1
{
private static SingletonV1 instance = null;
private SingletonV1()
{
}
public static SingletonV1 Instance
{
get
{
if (instance == null)
{
instance = new SingletonV1();
}
return instance;
}
}
}
// 第二个版本 —— 简单的线程安全
public sealed class SingletonV2
{
private static SingletonV2 instance = null;
private static readonly object padlock = new object();
SingletonV2()
{
}
public static SingletonV2 Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new SingletonV2();
}
return instance;
}
}
}
}
// 第三个版本 - 使用双重检查锁定尝试线程安全
public sealed class SingletonV3
{
private static SingletonV3 instance = null;
private static readonly object padlock = new object();
SingletonV3()
{
}
public static SingletonV3 Instance
{
get
{
if (instance == null)
{
lock (padlock)
{
if (instance == null)
{
instance = new SingletonV3();
}
}
}
return instance;
}
}
}
// [推荐版本]第四个版本 - 不太懒,不使用锁且线程安全
public sealed class SingletonV4
{
private static readonly SingletonV4 instance = new SingletonV4();
// 显式静态构造函数告诉C#编译器
// 不要将类型标记为BeforeFieldInit
static SingletonV4()
{ }
private SingletonV4()
{
Debug.Log("生成了SingletonV4单例");
}
public static SingletonV4 Instance
{
get
{
return instance;
}
}
}
// 第五版 - 完全懒惰的实例化
public sealed class SingletonV5
{
private SingletonV5()
{
}
public static SingletonV5 Instance { get { return Nested.instance; } }
private class Nested
{
// 显式静态构造告诉C#编译器
// 未标记类型BeforeFieldInit
static Nested()
{
}
internal static readonly SingletonV5 instance = new SingletonV5();
}
}
// 第六版 - 使用.NET 4的 Lazy 类型(依赖.NET 4)
//public sealed class SingletonV6
//{
// private static readonly Lazy<SingletonV6> lazy =
// new Lazy<SingletonV6>(() => new SingletonV6());
// public static Singleton Instance { get { return lazy.Value; } }
// private SingletonV6()
// {
// }
//}
// 第七版 - 泛型单例问题==>外部泛型必须new() ==> 泛型无法控制new()
public class SingletonV7<T> where T : new()
{
private static T instance;
public static T GetInstance
{
get
{
if (instance == null)
{
instance = new T();
}
return instance;
}
}
}
// 第八版 - 雨松Momo推荐写法(Unity写法)
public class SingletonV8 : MonoBehaviour
{
public static SingletonV8 instance;
static SingletonV8()
{
GameObject go = new GameObject("#Globa#");
DontDestroyOnLoad(go);
instance = go.AddComponent<SingletonV8>();
}
public void DoSomeThings()
{
Debug.Log("DoSomeThings");
}
void Start()
{
Debug.Log("Start");
}
// 外部调用
// MyScriptSingleton.instance.DoSomeThings();
}
// 第九版 - 公司中常见的单例模式(Unity写法)
public class SingletonV9 : MonoBehaviour
{
public static SingletonV9 s;
private void Awake()
{
s = this;
}
}
// 第十版 - Unity单例泛型 用法
/// <summary>
/// public class GameManager : SingletonMono<GameManager>
///{
///
/// public override void Awake()
///{
/// base.Awake();
///}
///
///public void GameStart()
///{
/// Debug.Log("GameStart");
///}
///}
/// </summary>
/// <typeparam name="T"></typeparam>
public class SingletonV10<T> : MonoBehaviour where T : Component
{
private static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<T>();
if (FindObjectsOfType<T>().Length > 1)
{
Debug.LogError("instance count > 1");
}
else if (instance == null)
{
GameObject obj = new GameObject(typeof(T).ToString());
instance = obj.AddComponent<T>();
Debug.Log("add instance");
}
}
return instance;
}
}
public virtual void Awake()
{
DontDestroyOnLoad(gameObject);
}
}
[特别说明]:
SingletonTest这个类不能上生产,只用作简单测试,违背了Unity的启动线程的初衷
特殊单例(Sqlite):
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mono.Data.Sqlite;
//sqlManager类 数据
//做和sqlite的交互
//数据库的增删改查
//从数据库拿到数据的处理
public class SqliteManager
{
#region 单例模式
//私有化sqlManager对象
private static SqliteManager instance;
/// <summary>
/// 对外提供给其他人调用这个唯一 对象的接口
/// </summary>
/// <returns>唯一 对象</returns>
public static SqliteManager GetInstance()
{
if (instance == null)
{
instance = new SqliteManager();
}
return instance;
}
//无参构造方法 私有化 防止外部进行实例
private SqliteManager()
{
}
#endregion
#region 数据库常用操作类的对象
//数据库连接类
private SqliteConnection con;
//数据库指令类
private SqliteCommand command;
//数据库读取类
private SqliteDataReader reader;
#endregion
#region 数据库常用方法封装类
/// <summary>
/// 打开数据库方法
/// </summary>
/// <param name="dataBaseName">数据库的名称</param>
public void OpenDataBase(string dataBaseName)
{
try
{
//数据库名称的优化
if (!dataBaseName.Contains(".sqlite"))
{
dataBaseName += ".sqlite";
}
//数据库路径拼接
string dataPath = "Data Source=" + Application.streamingAssetsPath
+ "/" + dataBaseName;
//实例化连接对象 对sqlconnection进行赋值
con = new SqliteConnection(dataPath);
//对conmmad进行赋值
command = con.CreateCommand();
//打开连接
con.Open();
}
catch (SqliteException e)
{
//打印错误日志
Debug.LogError(e.Message);
}
}
/// <summary>
/// 关闭数据库
/// </summary>
public void CloseDataBase()
{
try
{
if (con != null)
{
con.Close();
}
if (reader != null)
{
reader.Close();
}
}
catch (SqliteException e)
{
Debug.LogError(e.Message);
}
}
/// <summary>
/// 执行sql查询 增 删 改
/// </summary>
/// <param name="sqlString">执行增删改的sql语句</param>
public void RunSql(string sqlString)
{
try
{
//对command对象的commandText进行赋值
command.CommandText = sqlString;
//执行commandText中的sql语句
command.ExecuteNonQuery();
}
catch (SqliteException e)
{
Debug.LogError(e.Message);
}
}
/// <summary>
/// 查询单个数据
/// </summary>
/// <param name="sqlString">sql语句</param>
/// <returns>查询结果</returns>
public object SelectSingleData(string sqlString)
{
try
{
//对command的命令属性访问器进行赋值
command.CommandText = sqlString;
//进行单个查询操作
object returnData = command.ExecuteScalar();
//返回数据
return returnData;
}
catch (SqliteException e)
{
Debug.LogError(e.Message);
return null;
}
}
/// <summary>
/// 查询多个数据
/// </summary>
/// <param name="sqlString">sql指令</param>
/// <returns>返回查询结果</returns>
public List<ArrayList> SelectMultipleData(string sqlString)
{
//实例化list容器
List<ArrayList> result = new List<ArrayList>();
//对command对象的属性访问器 进行赋值
command.CommandText = sqlString;
//执行查询操作
reader = command.ExecuteReader();
while (reader.Read())
{
//每一档的数据信息
ArrayList temp = new ArrayList();
//当前档 所有信息的获取
for (int i = 0; i < reader.FieldCount; i++)
{
//存储当前档的信息到 ArrayList中
temp.Add(reader.GetValue(i));
}
//每一档信息加入List<ArrayList>
result.Add(temp);
}
reader.Close();
return result;
}
#endregion
}
参考文献:
Implementing the Singleton Pattern in C#
Implementing the Singleton Pattern in C#
雨松MOMO: