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

引用计数使用场景

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

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

	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. React Native之React速学教程(中)

    概述 本篇为<React Native之React速学教程>的第一篇.本篇将从React的特点.如何使用React.JSX语法.组件(Component)以及组件的属性,状态等方面进行讲解 ...

  2. JavaEE中表现层、持久层、业务层的职责分析(转载)

    表现层.持久层.业务层 注:本文转载于:http://www.blogjava.net/jiabao/archive/2007/04/08/109189.html 为了实现web层(struts)和持 ...

  3. 二十一、如何导入svg图片

    svg就相当于字体,如何将生成的svg导入到自己的项目中去呢? 1.将类似下面的文件放入自己的项目中: 2.生成的svg中有一个style.css文件,将里面的内容拷贝到你的css中,然后更改上图的路 ...

  4. MySQL MHA搭建

    MHA算是业内比较成熟的MySQL高可用解决方案,在MySQL故障切换过程中,MHA能做到自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义 ...

  5. mongodb数据库集合操作

    1:更新update update() 方法用于更新已存在的文档.语法格式如下: db.collection.update( <query>, <update>, { upse ...

  6. 【Leetcode】【Medium】Reorder List

    Given a singly linked list L: L0→L1→…→Ln-1→Ln,reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→… You must do thi ...

  7. kivy.org - Open source Python library for rapid development of applications

    kivy.org - Open source Python library for rapid development of applicationsthat make use of innovati ...

  8. npm安装及webpack打包小demo

    node(node.js) 安装 1.先从https://segmentfault.com/a/1190000004245357网站下载x64位的安装包node-v4.8.1-linux-x64.ta ...

  9. January 27 2017 Week 4 Friday

    Procrastination is the thief of time. 拖延是时光之贼. Procrastination is the thief of time, besides, it is ...

  10. FireFox浏览器Flash&视频下载工具推荐

    介绍 两款扩展组件:Flash and Video Download & Flash Video Downloader 一起使用,各有优缺点. Flash and Video Download ...