单例模式
这天,当我聚精会神的在想代码逻辑框架的时候,忽然一阵尖锐的巴掌与我后背快速接触的声音伴随着剧烈的疼痛打断了我的思考,我惊愕的转过头,发现她脸上有些生气,小嘴撅着,带着怒气看着我,我心里在问她:"干嘛?"
她也似乎听到了我内心的声音,说道:"刚刚有个大蚊子落在你身后我怕它咬你,我把它拍死了".
"哦,谢谢你".
她也不回答我,然后双臂圈着我的脖子,把小脑袋放在我的肩上,在我耳边说:"你在做什么呢?这么入神".
我说,我发现"单例模式"虽然使用很方便,但是一旦项目中出现了许多个单例模式,使用单例模式的脚本越多.可以访问的变量就越多,最后就会难以控制,造成的维护成本就越大,所以我在想如何有效的控制单例模式的数量."
"单例模式?单例模式是什么呀?为什么不能多用呀?".
哈哈,我就知道,她想知道这里面的道理,于是我转过去拉着她的手,对她说:"单利的意思就是不管有多少个脚本调用,而被调用的脚本始终保持唯一性".
"就是在某个地方就实例一次的意思吗?"
"对的".
"那为什么要这么做啊?"
"因为在有些情况中,A脚本需要拿到B脚本中的值,但是如果A脚本直接实例化B脚本的话,那么随便A对于B脚本的值怎么修改,但是对于B脚本本身是没有任何影响的".
"哦,那在你的游戏中该怎么理解呢?".
"哈哈,我说的太枯燥了吗?想听点游戏方面的事情?"
她不语
我接着说,"在游戏中就是一个英雄被攻击了,然后英雄掉血,英雄的类中有个BeAttack();方法,然后敌人1来攻击,敌人2来攻击,那么这个时候这两个敌人不能直接new一个英雄类,只能调用英雄本身挂载的类".
"那要是直接实例英雄类会怎么样啊?"
"那就英雄不会掉血呀.因为敌人操作的是实例化出来的英雄类,而并非英雄身上的英雄类"
"哦,我明白了,敌人操作的是英雄的分身 "
"哈哈,你还记得,但是不对哦,那是引用,这个就有点像双胞胎的意思了.它们虽然一样,但是彼此并不相同"
"哦"
我看了看她,把她拉到我的腿上坐着,继续和她说:"那么这个时候就得把英雄写成一个单利模式"
我转过去面对电脑,她也看着我的屏幕
我写下
private static Singleton _instance = null; public static Singleton Instance { get { if (_instance == null) { _instance = FindObjectOfType(typeof(Singleton)) as Singleton; } return _instance; } }
"这个就是单例模式了,如果我们再加入2个敌人的话就应该是这样."
"等一下,那个static,是干嘛的,为什么要写一个static啊"
"static是代表全局静态,就是说在这个项目中全局可访问,不需要new."
"不需要实例吗?"
"对的"
"哦"
"你看,enemy类这么写的"
public class enemy1 : MonoBehaviour { private void Start() { Singleton.Instance.Beack(this.gameObject , ); } } public class enemy2 : MonoBehaviour { void Start () { Singleton.Instance.Beack(this.gameObject, ); } }
"它们两个好像啊"
"对呀,它们都拿到了单例模式下英雄被攻击的方法,因为是测试,所以只是改了一个攻击的数值而已."
"嗯嗯"
"那么我们将他们部署好.然后运行一下"
你看英雄的被攻击方法就被这2个enemy调用到了.
"嗯嗯,好方便,只要写一句就可以调用里面的方法了"
"恰恰是因为这样所以这样做是不安全的"
"为什么它是不安全的啊?"
"因为这个单例是全局静态啊,任何一个地方都可以通过单例点出来被攻击的方法,如果用多了,整个项目中到处可见的Instance字段"
"就是因为instance字段多吗?就不用它了?"
"其实也不完全是,单例模式还违反了"开闭原则",这是直接操作本体,而不是它的接口"
"啊?开闭原则?"她有点晕.
"嗯嗯,就是类应该对扩展开放,对修改关闭,如果有新功能就直接在子类中写,避免再动父类,这是面向对象编程中很重要的思想."
"这里直接操作父类,它没有修改它的方法呀."
"但是,我们想这样的一个情况,假如刚刚的英雄被攻击方法加上一个"攻击免疫"的效果,那我们该怎么做呢?"
"修改刚刚的Beact"吗?"
"对呀,你看是不是直接违反了开闭原则,对功能扩展,对修改关闭,它直接修改了Beack方法呀"
"哦,原来是这样"她吐了吐舌
她果然很聪明,她连忙问了一句:"那如果把单例写成父类呢?子类继承父类,它们分别实现单例的功能".她迫不及待的说.
"通过父类的单利访问子类的单例"她顿了顿.然后看着我,满眼期待.可是她的方法并不是最优解.
"如果真的是这样做.那么我们也许会有这种情况,有个孙子类.那么孙子类她还是父类的对象吗?是不是已经是子类的对象了呢?那么单例模式应该是保证唯一对象啊,现在呢?"
她的眼睛渐渐迷离了起来,泛起一层红晕.
"啊,这样的嘛"
"对呀,滥用单例还有其他的坏处呢,比如:如果这个单例挂在了第二个物体上,就会出问题,还有永远不会被GC,代码耦合度变高。如果大量单例对象间交叉引用,会让代码变的很乱,不方便后续维护;而且工程如果大了之后,也不方便拆分工程,引起编译时间过长。可以适当的拆分重组一下功能,让引用尽可能变成单向的。也可以引入事件中心,来解耦合。
功能安全性。成员变量容易被其他地方随意修改,不好排查。某些方法可能是特定场合才使用的,但是其他人并不知道。线程安全。涉及到线程相关的操作,非常容易出事。"
"GC?是啥呀,是那个吗?"她坏笑着,把手伸进我的衣服里,开始肆意的抚摸.
我敲了她的头一下."当然不是,GC代表垃圾回收机制,即使这个单例别销毁,但是也不会被回收."
"哦,那好吧".她嘟囔着
过了会又说:"那单例模式不用的话,那么就需要获取组件和new的方式来进行脚本之间的联系吗?你就没有两全其美的方法嘛?"
"我当然有啦,如果我能知道这个类一共被new了多少次,一直限制它只有一个就好了."
public class Singleton { protected static int m_objCounter = ; protected bool m_bEnable = false; public Singleton() { m_objCounter++; if (m_objCounter >= ) m_bEnable = true; else m_bEnable = false; if (!m_bEnable) { Debug.LogError("当前的实例数已经超过1个"); } } public void Operator() { if (m_bEnable == false) { return; } Debug.Log("可以执行"); } }
那么在其他地方去实例多个单例的时候就会触发检测而导致调用失败
Singleton singleton1; Singleton singleton2; private void Start() { singleton1 = new Singleton(); singleton2 = new Singleton(); singleton1.Operator(); singleton2.Operator(); }
"emmm.那,这个就只能在一个类中使用喽.其他的地方使用不了的吧?"
"对的,因为只能实例一次嘛"
"我觉得这个并不好用啊,不如单例,没有单例模式灵活."
我连忙解释到:"因为有了限制,所以代码不会乱啊,不会出现到处都是Instance的情况啊,如果是个小型的项目,当然,怎么简单怎么来没错,可是如果是几百人合作的项目,谁也不敢到处都是单例呀."
"好吧,算你说的有道理,哼"
说完,她把手抽出来,跳了下去,问我,要不要喝水.我说:"要的,谢谢".
她白了我一眼,然后给我倒水去了.
2021年3月24日,主题为《数据的世界,世界的数据》的星环科技2021春季新品发布会...
前提条件 请您在购买前确保已完成注册和充值。详细操作请参见 如何注册公有云管...
从 10.0.0 版开始,异步迭代器就出现在 Node 中了,在本文中,我们将讨论异步迭...
信息化2.0时代提出开展智慧教育创新发展行动。2019年2月,中共中央、国务院印发...
在Python语言中有如下3种方法: 成员方法 类方法(classmethod) 静态方法(staticm...
本文整理自直播《Hologres 数据导入/导出实践-王华峰(继儒)》 视频链接: https:/...
建站 什么 虚拟主机 够用?这要看搭建的是什么类型的网站。比如个人博客类型的网...
Docker生成新镜像版本的两种方式 There are two ways Docker can generate new m...
【51CTO.com快译】 数据可视化工具不断发展,提供更强大的功能,同时改善可访问...
摘要 元旦期间 订单业务线 告知 推送系统 无法正常收发消息,作为推送系统维护者...