【代码篇】不要让单例毁了你的代码

“代码篇“系列文章旨在写出更优雅的代码。


单例模式,经典的23种设计模式之一。一个Instance想哪里调就哪里调。然而单例模式对整个工程的耦合性破坏很大,我认为是最糟糕的设计模式之一。今天想结合之前项目里的用到的单例来讲讲单例模式的问题。
项目里有个单例类叫作TimeScaleManager,是一个管理游戏里时间的一个类。有两个核心的接口用来获得deltaTimefixedDeltaTime

public float GetDeltaTime()
{
    
    
	......
}

public float GetFixedDeltaTime()
{
    
    
	......
}

为什么需要这个类来提供deltaTime,因为游戏里需要暂停之类的效果,其中暂停希望游戏逻辑暂停,但是UI不暂停。光unity提供的Time.deltaTime不足以实现。这个单例看上去没有什么问题,但是由于使用者的不注意。到我接触这部分的代码的时候,项目里已经到处充满了这样子的调用,大概有几百处的调用:

_currentTime += TimeScaleManager.instance.GetDeltaTime();

在这里插入图片描述
接下来,策划提了新需求:希望能够实现玩家正常速度敌人放慢速度的类似子弹时间的效果。这个时候我肯定需要去修改TimeScaleManager的调用处的代码了。需要让调用处区分是玩家在调用还是敌人在调用。发现问题了没有,有多少个地方调用就意味着要修改多少个地方,简直就是地狱。由此可以看出单例类最大的弊端:

破坏了类与类之间的耦合度,且调用单例的地方越多,破坏程度越大


第二个要谈的就是单例的销毁。单例如果没有及时销毁,里面对其它类的引用就会一直持有,GC的时候无法回收这部分内存占用,必定造成内存泄漏。所以使用单例类一定要加入类似下面的代码以对单例进行及时销毁:

public static bool DestroyInstance()
{
    
    
	if( _instance == null )
	{
    
    
		return false;
	}

	_instance = null;
	return true;
}

针对单例的种种弊端,我提出以下建议:

1. 减少单例类被其它类引用的次数。

比如上面TimeScaleManager的例子,修改前大概是这样子。 各个类都直接调用TimeScaleManager里的方法,导致修改寸步难行。
在这里插入图片描述
修改后变成了这样,玩家和敌人所有对TimeScaleManager的引用都来自与玩家和敌人的基类Actor,这样就算以后需要修改接口,我也只需要修改一个地方。

在这里插入图片描述


2. 使用扩展方法来代替单例调用。

之前看到一个对象池的代码,是这么写的:

public static void AllocateTo( this GameObject prefab, int count = 1 )
{
    
    
	PoolManager.instance.AllocateTo( prefab, count );
}

需要分配对象的时候直接prefab.AllocateTo() 就能使用,耦合性非常低,使用者甚至不需要知道单例的存在。这是一种好的写法。


3. 对于第三方库的单例,建议自己写个类把它包装起来。

Unity里面的Debug,如果项目里已经充满了大量的Debug.Log,这个时候来个需求,希望游戏里能实时控制打开关闭Log,或者需要打Log的同时把时间也打印出来,是不是修改起来也特别麻烦。所以对于Unity的单例或静态类,或者其它非开源的插件里的单例或静态类。建议自己写个类把它包装起来,以方便以后的修改。类似这样:

public static class MyDebug
{
    
    
	public static void Log( object message, Object context = null )
	{
    
    
		MyLogger.Log( "<b>Log: </b>" + message, context );
	}

	public static void LogFormat( string format, params object[] args )
	{
    
    
		MyLogger.LogFormat( "<b>Log: </b>" + format, args );
	}
}


既然都看到这里了,不如关注一下吧

关于作者:

  • 水曜日鸡,简称水鸡,ACG宅。曾参与索尼中国之星项目研发,具有2D联网多人动作游戏开发经验。

CSDN博客:https://blog.csdn.net/j756915370
知乎专栏:https://zhuanlan.zhihu.com/c_1241442143220363264
Q群:891809847

猜你喜欢

转载自blog.csdn.net/j756915370/article/details/106342482