引用计数是一个很好用的技术概念,不要被这个名字吓到了。首先来讲讲引用计数是干嘛的。

引用计数使用场景

有一间黑色的屋子,里边有一盏灯。当第一个人进屋的时候灯会打开,之后的人进来则不用再次打开了,因为已经开过了。当屋子里的所有人离开的时候,灯则会关闭。

我们先定义灯的对象模型:

	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

更多内容

Unity 游戏框架搭建 (二十二) 简易引用计数器的更多相关文章

  1. Unity 游戏框架搭建 2019 (十八~二十) 概率函数 & GameObject 显示、隐藏简化 & 第二章 小结与快速复习

    在笔者刚做项目的时候,遇到了一个需求.第一个项目是一个跑酷游戏,而跑酷游戏是需要一条一条跑道拼接成的.每个跑道的长度是固定的,而怪物的出现位置也是在跑道上固定好的.那么怪物出现的概率决定一部分关卡的难 ...

  2. # Unity 游戏框架搭建 2019 (十六、十七) localPosition 简化与Transform 重置

    在上一篇我们收集了一个 屏幕分辨率检测的一个小工具.今天呢再往下接着探索. 问题 我们今天在接着探索.不管是写 UI 还是写 GamePlay,多多少少都需要操作 Transform. 而在笔者刚接触 ...

  3. Unity 游戏框架搭建 (十) QFramework v0.0.2小结

    从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...

  4. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

    背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

  5. Unity 游戏框架搭建 (十三) 无需继承的单例的模板

    之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...

  6. Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介

    约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...

  7. Unity 游戏框架搭建 (十七) 静态扩展GameObject实现链式编程

    本篇本来是作为原来 优雅的QChain的第一篇的内容,但是QChain流产了,所以收录到了游戏框架搭建系列.本篇介绍如何实现GameObject的链式编程. 链式编程的实现技术之一是C#的静态扩展.静 ...

  8. Unity 游戏框架搭建 (十二) 简易AssetBundle打包工具(二)

    上篇文章中实现了基本的打包功能,在这篇我们来解决不同平台打AB包的问题. 本篇文章的核心api还是: BuildPipeline.BuildAssetBundles (outPath, 0, Edit ...

  9. Unity 游戏框架搭建 2019 (二十一、二十二) 第三章简介&整理前的准备

    整理前的准备 到目前为止,我们积攒了很多示例了,并且每个示例也都贯彻了最的约定和规则. 在上一篇的小结也说了一个比较新的东西:编程体验优化. 在之前我们还积攒了一个问题:代码重复问题. 我们可是忍住整 ...

随机推荐

  1. mysql三表联合查询

    -- SELECT d.userId, d.userPhoNum, a.orderId, a.productType, b.courseId, b.courseName, c.payJe -- FRO ...

  2. 配置centos7 网卡

    进入root模式,输入 cd /etc/sysconfig/network-scripts/ 按Tab键查看网卡配置文件名称,然后进入编辑: 如: cd /etc/sysconfig/network- ...

  3. 项目经验:GIS<MapWinGIS>建模第一天

    随便记录下项目的进展情况: GIS平台系统,实现整个供水系统的协调与统一.系统以管网为基础依据,建立可实现供水管网规划设计.输配管理.图档管理.抢修辅助决策及综合查询.统计等功能. 本文档的预期读者是 ...

  4. Python爬虫教程-23-数据提取-BeautifulSoup4(一)

    Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据,查看文档 https://www.crummy.com/software/BeautifulSoup/bs4/doc. ...

  5. 【Android】Warning :uninstalling will remove the application data!

    最近从Android Studio向手机发布项目过程中经常出现, 问题虽小,但是开发过程中确实浪费时间. It is possible that issue is resolved by uninst ...

  6. Windows下Python2与Python3两个版本共存的方法详解

    来源:http://www.jb51.net/article/105311.htm 这篇文章主要介绍了Windows下Python2与Python3两个版本共存的方法,文中介绍的很详细,对大家具有一定 ...

  7. maven学习(七)后续扩展、资料

    写这几篇博客的来源是 "maven实战 + 网上的博客 + 平时使用的心得 ".记录的都是比较常用的东西,也有一些只做了大概了解.或者干脆直接略过,在这里做一下总结,如果有需要在进 ...

  8. NFS-heartbeat-drbd模拟NFS高可用

    NFS介绍: NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS ...

  9. Spark Broadcast内幕解密:Broadcast运行机制彻底解密、Broadcast源码解析、Broadcast最佳实践

    本课主题 Broadcast 运行原理图 Broadcast 源码解析 Broadcast 运行原理图 Broadcast 就是将数据从一个节点发送到其他的节点上; 例如 Driver 上有一张表,而 ...

  10. 【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.2.虚拟机类加载机制

    1.概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验. 转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制. 2.类加载顺序 类从被加载到虚拟 ...