什么是单例模式
单例模式就是说,这个类只有一个对象。比如游戏中的Player,一个玩家只能有一个Player。
简单实现
class Player
{
public string name = "aaa";
#region MyRegion
//私有
private Player()
{
}
//2、在内部new一个单例,游戏一开始就会创建对象、
public static Player player = new Player();
#endregion
}
这是一个简单的实现。
可以通过Player.player
来访问单例对象。但是这样不安全,因为任何一个使用Player.player
的人都可以执行Player.player=null
这一操作。所以,有一个升级版的方案如下。
只读单例
class Player
{
public string name = "aaa";
#region MyRegion
//私有
private Player()
{
}
//2、在内部new一个单例,游戏一开始就会创建对象、
public static readOnly Player player = new Player();
#endregion
}
这样,Player.player
就成只读的了,但是这样设计虽然安全性升级了,但是会在游戏一开始就创建对象。如果有大量的单例,这样游戏开始就会创建大量的对象。所以有一个优化的方案。
单例模式,惰性返回一个实例
Class Player
{
public string name ="aaa";
//1、私有构造
private Player(string name)
{
this.name=name;
}
//2、创建一个静态的单例
private static Player instance;
//3、创建一个静态方法,惰性实例化返回单例
public static Player GetInstance(string name)
{
//惰性实例化;只有调用的时候才会实例化对象
if (instance == null)
{
Console.WriteLine("被实例化了");
instance = new Player(name);
}
Console.WriteLine("Get"+instance.name);
return instance;
}
}
这样只有调用Player类的时候才会创建单例对象。
思考
在学习惰性返回实例的单例时,有一个问题一开始没想通。
class Program
{
static void Main(string[] args)
{
Player player = Player.GetInstance("bbb");
Console.WriteLine("player"+player.name);
player = null;
Console.WriteLine("player是空"+(player==null));
Player player1 = Player.GetInstance("ccc");
Console.WriteLine("player1"+player1.name);
//Console.WriteLine(player1.name);
}
}
当我创建player1对象并打印其名字,然后再将其置为空。此时我再创建player1对象时,应该会创建一个新的对象。
但其实不是的,因为player对象里只是存的instance的地址,把player=null,也只是把player存的地址设为空而已,instance并不受影响。而且instance是存放在静态空间中的,不是存放在栈或堆中。
更简化的惰性实例化实现
class Singleton
{
private static Singleton instance;
public static Singleton Instance{
get{
if(null==instance){
instance=new Singleton();
}
return instance;
private Singleton()
{
}
}
内存分区
内存到底分几个区?
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由os回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。
5、程序代码区—存放函数体的二进制代码。

单例模板
如果一个项目中需要有很多单例,可以把单例抽象成一个父类作为模板。其他单例类直接继承这个模板即可。
public class SingleTon<T> where T : SingleTon<T>,new()
{
private static T instance;
public static T GetInstance()
{
if(instance == null)
{
instance = new T();
}
return instance;
}
}
public class GameAssetsMgr :SingleTon<GameAssetsMgr> {
/// <summary>
/// 加载装备预设体
/// </summary>
public GameObject LoadEquipItemPrefab()
{
//加载预设体
return Resources.Load<GameObject>("Prefabs/Equip");
}
/// <summary>
/// 通过装备名称加载装备图片
/// </summary>
/// <returns>The equip sprite.</returns>
/// <param name="equipName">Equip name.</param>
public Sprite LoadEquipSprite(string equipName)
{
return Resources.Load<Sprite>("Textures/" + equipName);
}
}
网友评论