Dirty Flag 模式及其应用
之前在开发中就发现“dirty”是一种不错的解决方案:可以用来延缓计算或者避免不必要的计算。后来在想,这应该也算一种设计模式吧,于是搜索“Dirty设计模式”,没有什么结果,然后换成英文“Dirty design pattern”,搜到了《game programming patterns》这本电子书。书中介绍了Dirty Flag 模式在游戏客户端的应用场景,如果英文不好,这里也有中文翻译。本文结合几个具体的例子,介绍什么是Dirty Flag 模式,并分析该模式的适用场景以及使用注意事项。
什么是Dirty Flag:
简单来说,就是用一个标志位(flag)来表示一组数据的状态,这些数据要么是用来计算,或者用来需要同步。在满足条件的时候设置标志位,然后需要的时候检查(check)标志位。如果设置了标志位,那么表示这组数据处于dirty状态,这个时候需要重新计算或者同步。如果flag没有被设置,那么可以不计算(或者利用缓存的计算结果)。另外,在两次check之间,即使有多次标志位的设置,也只需要计算一次。
因此,Dirty Flag模式的本质作用在于:延缓计算或数据同步,甚至减少无谓的计算或者同步。计算比较容易理解,对于同步,后面也会给出例子。在后面的描述中,除非特殊说明,计算也包含了同步。
Dirty Flag使用实例:
首先,《game programming pattern》中的例子非常形象生动,图文并茂,建议直接阅读原文,本文不再复述。接下来介绍几个其他的例子。
First
def set_need_tick(self, is_need):
self.need_tick = is_need def tick(self):
if self.need_tick:
self.do_tick() # do_tick 需要做大量的检查,较为耗时
def dummy_tick(self):
pass
def set_need_tick(self, is_need):
if is_need:
self.tick = self.do_tick
else:
self.tick = self.dummy_tick
Second
class cached_property(object):
""" A property that is only computed once per instance and then replaces
itself with an ordinary attribute. Deleting the attribute resets the
property. """ def __init__(self, func):
update_wrapper(self, func)
self.func = func def __get__(self, obj, cls):
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value
def set_property_dirty(self, property_name):
self.__dict__.pop(property_name, None)
在需要的时候调用这个设置函数就行了,在这个例子中,并没有对某个属性的设置和检查,但配合之前的cached_property,作用是很明显的:缓存计算结果,需要的时候重新计算。下面是完整测试代码
import functools, time
class cached_property(object):
""" A property that is only computed once per instance and then replaces
itself with an ordinary attribute. Deleting the attribute resets the
property. """ def __init__(self, func):
functools.update_wrapper(self, func)
self.func = func def __get__(self, obj, cls):
if obj is None: return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value class TestClz(object):
@cached_property
def complex_calc(self):
print 'very complex_calc'
return sum(range(100)) def __set_property_dirty(self, property_name = 'complex_calc'):
self.__dict__.pop(property_name, None) def some_action_effect_property(self):
self.__set_property_dirty() if __name__=='__main__':
t = TestClz()
print '>>> first call'
print t.complex_calc
print '>>> second call'
print t.complex_calc
print '>>>third call'
t.some_action_effect_property()
print t.complex_calc
cache property and dirty
Third
Fourth
Fifth
适用场景:
使用条件:
注意事项:
最新文章
- input 正则限制输入内容
- Oracle 11g服务详细介绍及哪些服务是必须开启的?
- Codeforces Round #282 Div.1 B Obsessive String --DP
- 看懂理解 keyboard中 , navigation的设置: 切换工作区和移动窗口到不同的工作区.
- 使用maven 如何生成源代码的jar包
- JAVA程序设计 实验一
- 【ZBar】ios错误ignoring file xxx missing required architecture x86_64 in file
- iOS Android图标生成器PHP
- 白书 4.1.2 模运算的世界 P291
- JS的注意点
- 使用SQLdiag Utility搜集SQL Server诊断信息
- pythonchallenge学到的python内置函数整理
- 图论算法-Dijkstra
- 【Android Developers Training】 24. 保存键值对
- ES6正则表达式扩展
- 异常-----java.sql.SQLException:ORA-01861:文字和格式字符串不匹配
- 第三篇:Python字符编码
- Arduino传感器学习目录
- 网易云通过KCSP认证,云原生技术实力再获认可
- Java03-Java语法基础(二)运算符
热门文章
- 【bzoj1552】[Cerc2007]robotic sort
- Incompatible pointer types assigning to &#39;id<;>;&#39; from &#39;Class&#39;错误
- ios UIKit动力 分类: ios技术 2015-07-14 12:55 196人阅读 评论(0) 收藏
- 7 -- Spring的基本用法 -- 12...
- MUI开发注意事项
- android 通过wifi 热点实现手机摄像头数据共享(转)
- java系列--重载和覆盖小结
- App外包开发周期一般多长?
- 9.TCP:传输控制协议
- --@angularJS--较复杂的指令嵌套demo——综合小实例:登陆界面