很高兴见到你!
上上周我在掘金碰巧遇到了一篇用设计模式管理状态的文章,一时兴奋不已,在评论区安利了,一直以来我司在封装商业级 SDK 时,使用的十六进制状态管理机制。
原以为会无人对此感兴趣,没想到,留言很快就收到文章作者的回复,并且在评论区耐心地和我探讨了设计模式的 独占式状态机,和十六进制的 复合状态管理 在使用场景上的区别。
遗憾的是,通过评论区的只言片语,并不能让人体会到 十六进制状态管理 的真正魅力。
于是作为回馈,我特地分享了这一篇:当我们封装商业级 SDK 时,我们是怎么使用十六进制来完成状态管理。
😉
此外,是只有封装 SDK 这种大动作,才值得使用十六进制吗?不是的,恰恰相反,正因为 十六进制状态管理是如此地普适,乃至于连封装 SDK 都优先使用这种方式。
考虑到部分读者可能对十六进制本身不太了解,本文会连同十六进制一起介绍。
所以如果阅读完这篇文章,你对 十六进制的状态管理 有了感性的认识,那我的愿望也就达到了。
1
also24 2019-07-03 13:53:40 +08:00 5
你这明明是二进制状态管理,关十六进制什么事情……
写成十六进制还不方便理解,要思考一下: private final int STATUS_1 = 0x0001; private final int STATUS_2 = 0x0002; private final int STATUS_3 = 0x0004; private final int STATUS_4 = 0x0008; 直接移位多方便: private final int STATUS_1 = 1 << 0; private final int STATUS_2 = 1 << 1; private final int STATUS_3 = 1 << 2; private final int STATUS_4 = 1 << 3; 或者干错手动补 0 也方便理解啊: private final int STATUS_1 = 0b1; private final int STATUS_2 = 0b10; private final int STATUS_3 = 0b100; private final int STATUS_4 = 0b1000; |
2
whileFalse 2019-07-03 13:55:48 +08:00 11
各位不用点进去了,就是把多个 bool 放到一个 int 里面。洋洋洒洒写了四千字。
|
3
busymilk 2019-07-03 13:59:12 +08:00
不是 flag 那一套么。。。
|
4
WebKit 2019-07-03 14:02:35 +08:00 via Android
这种文章写这么详细,应该比较适合刚入门什么都不会的。
|
5
KunMinX OP |
6
AndroidEngineer 2019-07-03 14:24:15 +08:00
来点高端的,比如 dex 热修,so 混淆加密,现在 Android 不往底层走等于菜鸡
|
7
ShangShanXiaShan 2019-07-03 14:32:34 +08:00
@AndroidEngineer "你很棒"警告
|
8
Lucups 2019-07-03 14:53:06 +08:00
感叹号结尾的文章标题一律不看
|
9
ys1992 2019-07-03 14:57:23 +08:00 1
楼主分享思路不错,赞一个!一楼优化解释也很好,确实更通用且便于理解吧,本质都是通过位运算来解决多状态集合问题
|
11
agostop 2019-07-03 15:08:05 +08:00
之前在一个接口上用过类似的算法,和题主描述的场景差不多,不过是用的二进制……没看懂为什么非要用 16 进制?
|
12
ice000 2019-07-03 15:11:07 +08:00
标题党
|
13
zjiecode 2019-07-03 15:13:44 +08:00
感谢楼主,虽然很基础,但是还是很不错的,另外,权限之类的,也可以考虑这种思想。
不过,要是状态超过了 32,就用 long,那超过 64 了呢?有没有啥好的解法呢? |
14
KunMinX OP @Lucups @ostholz @ice000
那你很棒哦 @ys1992 @mrjiejiejie 感谢你的阅读! 我司目前封装的 SDK,一个功能的状态一般不超过 12 个,所以就算 int 也足够。 64 个状态的话,到底是什么功能才会存在这样的设计呢? |
15
SuperNovaSonic 2019-07-03 15:24:35 +08:00
来自掘金:
|
16
SuperNovaSonic 2019-07-03 15:24:44 +08:00 1
金 1998
你应该没怎么玩过 C 语言 21 分钟前 KunMinXlv-3(作者) Android @ ViaBus-Architecture 回复 金 1998: 那你很棒哦 4 分钟前 |
17
KunMinX OP |
18
yusuzhan 2019-07-03 15:55:20 +08:00
这个东西在 Java 里很常用,叫做位掩码。
|
19
alextang95 2019-07-03 16:02:52 +08:00
@KunMinX 这种状态处理属于基本操作。
C 语言用的更多,因为要用那么一点点内存作更多的事。 另外这和十六进制没什么关系,就是二进制状态。 状态的转移用位运算。 @also24 @whileFalse 二位省了大家好多时间,感谢 |
20
lastpass 2019-07-03 16:06:07 +08:00 via Android 1
楼主快坐下,快坐下。
不过一些常规操作而已。 快翻开你大学时候的计算机导论, c 语言基础, 汇编基础的书的前两章温习一下。 |
21
cizeZSY 2019-07-03 16:06:14 +08:00 via Android
这不是很常见的东西吗。。。
|
22
quaack 2019-07-03 16:11:39 +08:00
哈哈哈哈营销鬼才,这不是最简单的位运算吗
要是楼主知道各种 bit magic 可能会吹上天吧 |
23
quaack 2019-07-03 16:12:30 +08:00
|
24
maninfog 2019-07-03 16:15:33 +08:00 via iPhone
很棒的文章,支持一个。
|
25
Mithril 2019-07-03 16:16:46 +08:00
上古时代 Windows API 里的各种 HRESULT 不就是这么干的么。。。
|
26
xenme 2019-07-03 16:17:37 +08:00
|
27
alextang95 2019-07-03 16:19:38 +08:00
感觉我有点歪楼了,抓紧掰回来
1. 给 LZ 的分享精神点赞 2. 反应比较平淡的是见多了就不惊讶了 3. 恰到好处地解决问题的感觉很爽 4. 文章是有点啰嗦哈 5. 1L 讲的是挺棒的啊…… LZ 别 block 我…… |
28
lastpass 2019-07-03 16:33:04 +08:00 via Android
另外:我再补充一下。为何用二进制的形式存储状态被淘汰,除非是状态特别多,否则大家都不会使用的原因。
因为现代级的 CPU 寄存器非常之多,还有大量的 l1,l2,l3 缓存,这些状态会大部分情况下会被缓存到 cpu 的寄存器。直接从寄存器取数据可比 cpu 从内存里面取快多了。而且,很多时候。我们通常都只需要某个状态。直接取值和算一遍再获得值,后者的效率明显会略低(虽然大部分情况下,这点速度差距可以忽略) |
29
lastpass 2019-07-03 16:35:17 +08:00 via Android
当然,更重要的原因是,用二进制存储状态,太特喵不直观,代码阅读起来太费劲了。所以,大家都不愿意使用这个东西。
|
30
huijiewei 2019-07-03 17:22:50 +08:00 via iPhone
位运算非要强行扭成 16 进制,写技术文章最好多参考
|
32
no1xsyzy 2019-07-04 10:07:22 +08:00
@mrjiejiejie 编程珠玑里面不是有过了吗?状压存电话号码,何止 64 个状态,是 1,000,000 个以上的状态,全按位压缩。
|
33
no1xsyzy 2019-07-04 10:22:15 +08:00
《编程珠玑》( Programming Pearls )
《算法心得:高效算法的奥秘》( Hacker's Delight ) 这些方法现在越来越少了,原因: 1. 内存不缺了 2. #28 缓存更快 3. 影响可读性 4. 现在编程语言常常提供 Set 类型,可以兼具高效和可读性 老古董 Pascal 就支持 set of <enumerable>,可以当作位压编译期展开(可能需要看具体实现)。 甚至可以定义 enum 类型然后做集合,不比你这直观得多? https://en.wikibooks.org/wiki/Pascal_Programming/Sets |
34
no1xsyzy 2019-07-04 10:36:49 +08:00
另一方面,为何采用 8 个 status (无论是 bool 还是位压 int )标记按钮可用性是逻辑上错误的。
不应该上游控制下游,而应该下游因变于上游。 fn (ui:UI).setModeA(){ ui.mode = A; ui.updateButtonsAvailability(); } // same for modeB, modeC fn (ui:UI).updateButtonsAvailability(){ for(button in ui.buttons){ button.updateAvailability(mode=ui.mode) }} fn (button:Button).updateAvailability(mode:EnumMode){ button.availability = mode in button.availableModes } |
35
keymao 2019-07-04 11:05:41 +08:00 1
还是那句话 有事儿说事儿,上来就是这也简单那也存在,人家就是分享点东西而已,有错误可以合理指出,不足之处补正,愿意讨论讨论,不愿意讨论看看关了就完了,来句不甜不咸的很简单书本里有,有啥意思么? 愁了。 讨论问题,能不能别像个小孩一样。
|
36
mmdsun 2019-07-05 08:17:52 +08:00 via Android
Mark。二进制状态?
|
37
nicoljiang 2019-07-05 18:56:01 +08:00
@keymao 可能是因为楼主没管理好读者的预期(标题起的太大)
|
38
karllynn 2019-07-06 16:46:43 +08:00
楼主你没学过 C 语言么…
bit flag 是基本知识吧 |