[脚本]单利模式的实现 【转】
在游戏编程中常常遇到这样的问题,以unity3d为例,譬如场景中只有一个的物体:主
角,用做得分显示的UI。要随时获取这些对象不可能每次调用的时候使用类似unity中“Find”函数,这样做低效率;建一个公共类添加一个公有静态变
量来保存这些对象也可以,可是如果随着这些对象的增多维护起来困难且耦合度高不利团队开发,不怎么地道。我们想要的是这样:用到它时可以立即访问到它不需
要查找,这个对象与其他对象不相关不需要在其他地方建立索引来使用 。单例模式就是做这个。
单利模式实用意义就是客户代码可以随时访问而无需进行实例化查找等操作。模式中重点就是怎样维持/获取这个唯一的对象;通俗点就是怎样使用“类名.方法名”的形式访问而不是“实例名.方法名”的形式访问,要点就是在类的内部实例化自己/返回自己的实例。
使用“类名.方法名”访问形式大家知道的C#能做到这样的是公有静态成员,包括:公有静态变量,公有静态属性,公有静态函数。下面就是这几种情况下的实现方式。
方法一 :公有静态成员变量,在Awake函数中以赋值
代码如下:
- public class ClassA : MonoBehaviour
- {
- public static ClassA instance ;
- void Awake()
- {
- //if (instance != null) //判断是否已赋值
- //{
- instance = this ;
- //}
- }
- }
使用:ClassA.instance.XXX() ; ( XXX()表示方法 )
简介:
ClassA 在Awake()调用的时候才给instance 赋值,即在其他脚本的Awake()之前或者之中ClassA 并不能保证instance 不为null。所以此种方法调用的时候必须保证ClassA 的 Awake()函数调用之后。
方法二 :公有静态属性,属性get()中完成赋值
代码如下:
- public class ClassA : MonoBehaviour
- {
- public static ClassA _instance ;
- public static instance
- {
- get
- {
- if ( _instance != nul )
- {
- _instance = FindObjectOfType(typeof( ClassA ));
- }
- return _instance ;
- }
- }
- }
使用:ClassA.instance.XXX() ; ( XXX()表示方法 )
简介:
静态属性访问,上面这采用了一种延迟的处理方法,即在需要的时候才给_instance 赋值,客户代码无需担心_instance是否已经赋值,因为代码会保证你需要的时候不为null。
方法三 :静态构造器,构造期间完成赋值操作
代码如下:
- public class ClassA : MonoBehaviour
- {
- public static ClassA instance ;
- static ClassA ()
- {
- _instance = this;
- }
- }
使用:ClassA.instance.XXX() ; ( XXX()表示方法 )
简介:
这种方法使用C#特有的静态构造函数,其在类首次访问的时候调用,即当你访问此类的时候它第一件事就是调用此函数而且仅仅调用一次!如使用方法中示例的:ClassA.instance.XXX() ; 访问ClassA的instance成员之前已经调用了static ClassA () 静态构造器;此也是一种延迟处理的方法,需要注意的是静态构造器由于是构造函数其仅仅调用一次,是不会调用第二次。
需要指出的是,以上方法虽各自的利弊不相同,可是它们在unity3D有一个共同的弊端。静态成员的生存期为整个应用的生存期,即在unity3D中只有当退出程序时候才会回收这片内存,而unity3D中场景加载或者卸载的时候并不会回收这里,以例2为例:每次访问属性instance的时候都会判断“if ( _instance != nul )”,事实上运行一次_instance不为空之后如果不手动置为空其永远不会为空即时场景卸载!但是场景场景卸载之后_instance指向的对象实例会被销毁!那么这个_instance地址会指向一个错误的地方,导致程序会出现空引用的错误(注意:如果判断 is null 是没用的,它有地址不是空,可地址指向的地方不对,所以报空。)。解决上面的方法很多,传统的方式是添加一个公共管理器在场景跳转的时候将其置为null,不是此篇重点 略。。。~~ 有点绕口也不知道写明白了没,写过委托/事件的应该会碰到这情况,不明白的追问可。。。。。。
浙公网安备 33010602011771号