Unity 游戏框架搭建 (二十二) 简易引用计数器
引用计数是一个很好用的技术概念,不要被这个名字吓到了。首先来讲讲引用计数是干嘛的。
引用计数使用场景
有一间黑色的屋子,里边有一盏灯。当第一个人进屋的时候灯会打开,之后的人进来则不用再次打开了,因为已经开过了。当屋子里的所有人离开的时候,灯则会关闭。
我们先定义灯的对象模型:
class Light
{
public void Open()
{
Log.I("灯打开了");
}
public void Close()
{
Log.I("灯关闭了");
}
}
很简单就是两个方法而已。
再定义屋子的类,屋子应该持有一个Light的对象,并且要记录人们的进出。当有人进入,进入后当前房间只有一个人的时候,要把灯打开。当最后一个人离开的时候灯要关闭。
代码如下:
class Room
{
private Light mLight = new Light();
private int mPeopleCount = 0;
public void EnterPeople()
{
if (mPeopleCount == 0)
{
mLight.Open();
}
++mPeopleCount;
Log.I("一个人走进房间,房间里当前有{0}个人",mPeopleCount);
}
public void LeavePeople()
{
--mPeopleCount;
if (mPeopleCount == 0)
{
mLight.Close();
}
Log.I("一个人走出房间,房间里当前有{0}个人", mPeopleCount);
}
}
很简单,我们来看下测试代码。
var room = new Room();
room.EnterPeople();
room.EnterPeople();
room.EnterPeople();
room.LeavePeople();
room.LeavePeople();
room.LeavePeople();
room.EnterPeople();
看下输出的结果:
灯打开了
一个人走进房间,房间里当前有1个人
一个人走进房间,房间里当前有2个人
一个人走进房间,房间里当前有3个人
一个人走出房间,房间里当前有2个人
一个人走出房间,房间里当前有1个人
一个人走出房间,房间里当前有0个人
灯关闭了
灯打开了
一个人走进房间,房间里当前有1个人
OK.以上就是引用计数这项计数的使用场景的所有代码。
测试的代码比较整齐,很容易算出来当前有多少个人在屋子里,所以看不出来引用计数的作用。但是在日常开发中,我们可能会把EnterPeople和LeavePeople散落在工程的各个位置。这样就很难统计,这时候引用计数的作用就很明显了,它可以自动帮助你判断什么时候进行开灯关灯操作,而你不用写开关灯的一行代码。
这个例子比较接近生活,假如笔者再换个例子,我们把Light对象换成资源对象,其开灯对应加载资源,关灯对应卸载资源。而屋子则是对应资源管理器,EnterPeople对应申请资源对象,LeavePeople对应归还资源对象。这样你只管在各个界面中申请各个资源,只要在界面关闭的时候归还各个资源对象就可以不用关心资源的加载和卸载了,可以减轻大脑的负荷。
简易计数器实现:
计数器的接口很简单,代码如下:
public interface IRefCounter
{
int RefCount { get; }
void Retain(object refOwner = null);
void Release(object refOwner = null);
}
Retain是增加引用计数(RefCount+1),Release减去一个引用计数(RefCount—)。
在接下来的具体实现中,当RefCount降为0时我们需要捕获一个事件,这个事件叫OnZeroRef。
代码如下:
public class SimpleRC : IRefCounter
{
public SimpleRC()
{
RefCount = 0;
}
public int RefCount { get; private set; }
public void Retain(object refOwner = null)
{
++RefCount;
}
public void Release(object refOwner = null)
{
--RefCount;
if (RefCount == 0)
{
OnZeroRef();
}
}
protected virtual void OnZeroRef()
{
}
}
以上就是简易引用计数器的所有实现了。
接下来我们用这个引用计数器,重构灯的使用场景的代码。
class Light
{
public void Open()
{
Log.I("灯打开了");
}
public void Close()
{
Log.I("灯关闭了");
}
}
class Room : SimpleRC
{
private Light mLight = new Light();
public void EnterPeople()
{
if (RefCount == 0)
{
mLight.Open();
}
Retain();
Log.I("一个人走进房间,房间里当前有{0}个人",RefCount);
}
public void LeavePeople()
{
// 当前还没走出,所以输出的时候先减1
Log.I("一个人走出房间,房间里当前有{0}个人", RefCount - 1);
// 这里才真正的走出了
Release();
}
protected override void OnZeroRef()
{
mLight.Close();
}
}
测试代码和之前的一样,我们看下测试结果:
灯打开了
一个人走进房间,房间里当前有1个人
一个人走进房间,房间里当前有2个人
一个人走进房间,房间里当前有3个人
一个人走出房间,房间里当前有2个人
一个人走出房间,房间里当前有1个人
一个人走出房间,房间里当前有0个人
灯关闭了
灯打开了
一个人走进房间,房间里当前有1个人
好了,今天就到这里
转载请注明地址:凉鞋的笔记:liangxiegame.com
更多内容
QFramework 地址:https://github.com/liangxiegame/QFramework
QQ 交流群:623597263
Unity 进阶小班:
- 主要训练内容:
- 框架搭建训练(第一年)
- 跟着案例学 Shader(第一年)
- 副业的孵化(第二年、第三年)
- 权益、授课形式等具体详情请查看《小班产品手册》:https://liangxiegame.com/master/intro
- 主要训练内容:
关注公众号:liangxiegame 获取第一时间更新通知及更多的免费内容。

Unity 游戏框架搭建 (二十二) 简易引用计数器的更多相关文章
- Unity 游戏框架搭建 2019 (十八~二十) 概率函数 & GameObject 显示、隐藏简化 & 第二章 小结与快速复习
在笔者刚做项目的时候,遇到了一个需求.第一个项目是一个跑酷游戏,而跑酷游戏是需要一条一条跑道拼接成的.每个跑道的长度是固定的,而怪物的出现位置也是在跑道上固定好的.那么怪物出现的概率决定一部分关卡的难 ...
- # Unity 游戏框架搭建 2019 (十六、十七) localPosition 简化与Transform 重置
在上一篇我们收集了一个 屏幕分辨率检测的一个小工具.今天呢再往下接着探索. 问题 我们今天在接着探索.不管是写 UI 还是写 GamePlay,多多少少都需要操作 Transform. 而在笔者刚接触 ...
- Unity 游戏框架搭建 (十) QFramework v0.0.2小结
从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...
- Unity 游戏框架搭建 (十六) v0.0.1 架构调整
背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...
- Unity 游戏框架搭建 (十三) 无需继承的单例的模板
之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...
- Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介
约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...
- Unity 游戏框架搭建 (十七) 静态扩展GameObject实现链式编程
本篇本来是作为原来 优雅的QChain的第一篇的内容,但是QChain流产了,所以收录到了游戏框架搭建系列.本篇介绍如何实现GameObject的链式编程. 链式编程的实现技术之一是C#的静态扩展.静 ...
- Unity 游戏框架搭建 (十二) 简易AssetBundle打包工具(二)
上篇文章中实现了基本的打包功能,在这篇我们来解决不同平台打AB包的问题. 本篇文章的核心api还是: BuildPipeline.BuildAssetBundles (outPath, 0, Edit ...
- Unity 游戏框架搭建 2019 (二十一、二十二) 第三章简介&整理前的准备
整理前的准备 到目前为止,我们积攒了很多示例了,并且每个示例也都贯彻了最的约定和规则. 在上一篇的小结也说了一个比较新的东西:编程体验优化. 在之前我们还积攒了一个问题:代码重复问题. 我们可是忍住整 ...
随机推荐
- Vue引入第三方JavaScript库和如何创建自己的Vue插件
一 第三方JavaScript库 前言 .vue文件 中不解析 script标签引入js文件,只能用 import 引入 有两种用法: 1.import a from '../a' 2.import ...
- inline-block元素,在同一行上下显示
两个元素使用了inline-block,并列显示时,会上下显示,给人感觉不在同一行 原因:其中一个元素使用了overflow:hidden,导致了基线变更 解决:1.另一个元素也添加overflow: ...
- 转:hive面试题
有一张很大的表:TRLOG该表大概有2T左右TRLOG:CREATE TABLE TRLOG(PLATFORM string,USER_ID int,CLICK_TIME string,CLICK_U ...
- hdu 1162 Eddy's picture (Kruskal 算法)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1162 Eddy's picture Time Limit: 2000/1000 MS (Java/Ot ...
- git 回滚到上个版本命令以及忽略某些文件提交
1.git回滚到上个版本 git reset --hard FETCH_HEAD 2.git忽略某些文件的提交 以前是用默认的.gitignore 然后再里面默认某些文件不提交.但是有个问题,.git ...
- IE Edge 下载文件的时候,文件名不能有windows不支持的特殊字符
IE Edge 下载文件的时候,文件名不能有windows不支持的特殊字符,比如:等. 马了个批的,其他浏览器包括IE就可以自动转换,比如:会自动变为_.
- 批量备份mysql数据库(shell编程)
#!/bin/bash DBPATH=/mysqlbak MYUSER=root MYPASS= SOCKET=/var/lib/mysql/mysql.sock MYCMD="mysql ...
- 在Ubuntu16.04.4上安装docker
在Ubuntu16.04.4上安装docker 一.环境准备 首先我们需要一台Ubuntu16.04 虚拟机或者真机,其次,我们对其进行环境配置. 1.1.移除已经安装过的dock ...
- sql执行计划变更和删除缓存中执行计划的方法
将指定SQL的执行计划从共享池删除的方法 http://www.2cto.com/database/201204/126388.html Oracle SQL执行计划变更的问题 http://www. ...
- 取多个name值相同的input里面的值
html 中是允许多个具有相同name属性的元素的,例如服务器端读取的常规做法是: string name = Request.Params["txtName"]; 得到的将是一串 ...