多變量邏輯表達(dá)式化簡原理與應(yīng)用:卡諾圖化簡法
1、背景
本文主要介紹使用卡諾圖化簡多變量邏輯表達(dá)式的原理與方法,此方法是一種邏輯計(jì)算思想,在任意技術(shù)平臺(tái)類似的多元化場景中均可適用。
本文以客戶端的一個(gè)業(yè)務(wù)場景為例,從舉例分析到實(shí)際應(yīng)用的步驟,介紹卡諾圖工具的使用,讓我們輕松應(yīng)對(duì)復(fù)雜交互或多條件判斷的編碼。
2、使用場景舉例
開發(fā)中我們有時(shí)會(huì)遇到一些復(fù)雜條件的交互要求,它們共同操作公共控件,使得交互邏輯在流程中變得極為復(fù)雜,如何簡便高效地處理和維護(hù)這些判斷邏輯,是我們可以思考的方向。
先來看一個(gè)這樣的業(yè)務(wù)場景,為方便說明已稍作簡化。在一個(gè)拍攝頁面中有如下幾個(gè)控件:添加音樂按鍵,濾鏡按鍵,拍攝鍵,特效選擇器,特效清除鍵?(圖1.1 所示紅圈處),它們?cè)谂恼站途w狀態(tài)下是都顯示的,然后用戶可能的操作流程有2種:拍照片和拍視頻,而這2種操作可以分別有3個(gè)不同的效果選擇:增加音樂,增加濾鏡,增加特效,則此例中共有 2 * 3 = 6? 種不同操作方式的組合,這些操作又分別涉及不同的控件,需要它們配合完成相應(yīng)操作。即 m 種操作和 n 種效果,共 m*n 種組合方法。
而聰明的你則要處理它們?nèi)康慕换ミ壿嫛4隧撁娓嘣敿?xì)的交互要求可參考發(fā)布工具[拍攝頁] 交互要求 [1]。
圖 1.1 拍攝頁的不同狀態(tài)UI與交互效果示意
主要交互要求是什么呢?參考看著上圖,我們隨便舉幾個(gè)粟子好了,比如:
?? 已拍了照片或視頻不能顯示音樂鍵
?? 濾鏡浮層打開后要隱藏音樂鍵、拍攝鍵和特效選擇器
?? 關(guān)閉浮層后要把這些控件重新顯示出來
?? 有特效時(shí)要顯示清除鍵
還有其他更多細(xì)節(jié)限于篇幅就不羅列了。多樣化的操作帶來邏輯的復(fù)雜變化,比如視頻拍了一半,暫停來切換特效,而特效控件在有視頻和無視頻時(shí)展示的控件又不同,或刪掉視頻去選濾鏡、選音樂等等,是不是已經(jīng)暈了?這里面還有些其他可能想都想不到的細(xì)節(jié)出現(xiàn),由此足以看出交互要求的復(fù)雜性了。如圖1.1 所示,紅圈處為頁面在不同狀態(tài)下發(fā)生的主要變化。
使用響應(yīng)式編程或許可以解決部分問題,但由于每個(gè)控件狀態(tài)并不是由單一參數(shù)決定的,所以我們?nèi)孕枰谒鼈兏髯缘谋O(jiān)聽方法里寫全部相關(guān)參數(shù)的判斷邏輯,這模式對(duì)解決此場景的根本問題似乎并無太多幫助。主要問題出在哪兒呢?
2.1 痛點(diǎn)
一句話總結(jié)問題:不同的交互方法之間產(chǎn)生了冗余的先后依賴而阻礙了業(yè)務(wù)的狀態(tài)轉(zhuǎn)移,使邏輯不夠清晰,代碼難以維護(hù)。
怎么辦呢?你可能會(huì)說,我們可以按操作的內(nèi)容來分類,把控件按操作類別分裝入不同的父容器中,然后在相應(yīng)操作方法里控制這容器即可。
嗯想法很不錯(cuò),但實(shí)際這么做了然后我們會(huì)發(fā)現(xiàn),例如說在上述場景里,在關(guān)閉浮層時(shí),若已經(jīng)拍了一段視頻,則還需要單獨(dú)判斷音樂鍵的顯示狀態(tài),或是此時(shí)還沒選擇特效,就不能把清除鍵也顯示出來。
于是我們開始意識(shí)到,這個(gè)場景下的業(yè)務(wù)方法不能完全獨(dú)立出來使用。抽象來說,這些操作之間相互有順序的依賴,它們不能嚴(yán)格滿足邏輯表達(dá)式加法交換律,即某些情況 A操作 和 B操作 的順序不同會(huì)導(dǎo)致結(jié)果不同:
還有許多類似的corner case,我們?nèi)舭讶縞ase分列出來,則它們的控制邏輯會(huì)像星辰一樣散落在各個(gè)處理方法中,作為中介作用的容器也會(huì)層層疊疊地出現(xiàn),然后我們還需要寫一大坨處理各種子狀態(tài)、容器控件的方法,再根據(jù)當(dāng)前用戶操作去相應(yīng)地調(diào)用;當(dāng)頁面里的控件數(shù)量增多,或需求變化了,或控件要增多/減少時(shí),整個(gè)流程就不再具有清晰的層級(jí)關(guān)系或先后邏輯了。
更麻煩的是,我們每次看似簡單的增刪改操作,都要把相應(yīng)業(yè)務(wù)的上下游方法全部梳理一遍,甚至和其他功能有交互的地方,也要關(guān)注到,這樣的邏輯產(chǎn)生過高的復(fù)雜度也容易產(chǎn)生疏漏。要維護(hù)好這么一堆面條代碼將不是一件令人愉快的事;若是對(duì)業(yè)務(wù)不熟悉就做修改,極易踩坑,導(dǎo)致改了A處又壞了B處,修了B處又影響了C處,正是因?yàn)楦髯訕I(yè)務(wù)的方法存在過度耦合,出bug就沒完沒了。
那么我們還有更優(yōu)雅的方式來處理這種場景么?
2.2 邏輯狀態(tài)抽象
不如我們先換個(gè)角度來看。
通過觀察梳理業(yè)務(wù)要求[1]可發(fā)現(xiàn),其實(shí)我們并不需要知道用戶之前做過什么操作,因?yàn)榭丶慕换ブ慌c個(gè)別參數(shù)相關(guān),即交互是依賴于某個(gè)變量而非業(yè)務(wù)流程。我們?nèi)魧⑦@些參數(shù)用bool值來確定,就可以唯一決定當(dāng)前的頁面狀態(tài),并且這些狀態(tài)在一個(gè)交互中是相互獨(dú)立的,即當(dāng)前狀態(tài)與它之前的狀態(tài)無關(guān)。
也就是說:與其說當(dāng)前操作需要什么交互,不如說當(dāng)前操作發(fā)生時(shí),相關(guān)參數(shù)處于什么狀態(tài),再由這些狀態(tài)即可決定頁面所需的交互。
例如,當(dāng)濾鏡浮層dismiss時(shí),哪些控件需要重新顯示出來呢?那得看此時(shí)是否已有錄視頻,是否已有特效,是否已有音樂等等,這些參數(shù)綜合起來,就唯一決定了當(dāng)前的狀態(tài),就可計(jì)算出所需邏輯。
很棒,我們走到這里問題已解決一大半了。即引出本文主題:卡諾圖。
2.3 狀態(tài)化簡工具:卡諾圖
若是滿足上述這些條件,那么我們就可以使用邏輯表達(dá)式來方便地描述它們,而邏輯式的化簡就可以用卡諾圖方便地完成。
至此,我們就將問題由具體業(yè)務(wù)流程轉(zhuǎn)化為:如何使用關(guān)聯(lián)的變量建立邏輯式描述頁面的狀態(tài)。這樣一來就把狀態(tài)從流程中剝離出來了,你會(huì)發(fā)現(xiàn),從這個(gè)角度看問題,無論流程怎么變,所做操作最終都會(huì)落入某個(gè)狀態(tài),這才是我們要找的關(guān)鍵聯(lián)系:
相關(guān)變量 --(確定)--> 邏輯表達(dá)式 --(確定)--> 控件狀態(tài)
這個(gè)過程,也是我們計(jì)算狀態(tài)轉(zhuǎn)移的方法,只用上面3步,掌握之后再遇到類似場景,我們完全可以無腦按套路來處理邏輯狀態(tài)就ok了,讓代碼清爽簡潔,敏感肌也能用。
2.4 舉例使用
卡諾圖具體怎么用呢?
我們還是繼續(xù)看上面的例子,就寫一個(gè)方法 :func refreshCurrentStatusUI(),用于在任意時(shí)刻需要刷新頁面狀態(tài)時(shí)獲得所需狀態(tài),而不用關(guān)心具體當(dāng)前的操作或流程是什么,以便把狀態(tài)從業(yè)務(wù)流程中獨(dú)立出來。
方法結(jié)構(gòu)也是最基本的思路,方法有格式如下:
在實(shí)際應(yīng)用的方法體里,把與業(yè)務(wù)場景相關(guān)的參數(shù)狀態(tài)列出來,比方說,獲取與羅列的控件相關(guān)的幾個(gè)必需變量,為了表述方便,這里用符號(hào)ABC來代表參數(shù),當(dāng)然你也可以用其他的符號(hào)。
各參數(shù)說明如下:
A:是否有視頻
B:是否有特效
C:是否有子特效
D:是否已拍照填充了子特效
F:是否有音樂
按上述方式填充方法體,有幾個(gè)參數(shù)你就列出幾個(gè),簡單又直觀:
有一點(diǎn)細(xì)節(jié)需要注意的是:上述變量用到的值一定要在方法體里即用即取,不建議從方法外傳值進(jìn)來,因?yàn)槎嗑€程和并發(fā)的存在,則有的屬性變量值可能在本方法開始調(diào)用后被其他線程或方法修改,即狀態(tài)已發(fā)生了改變,而傳入的值狀態(tài)就已經(jīng)滯后,導(dǎo)致本方法計(jì)算出的控件狀態(tài)不是預(yù)期最新的狀態(tài)了。
然后我們只需要繼續(xù)在這個(gè)方法里,使用上述變量當(dāng)下的值,計(jì)算每個(gè)控件狀態(tài)的邏輯表達(dá)式,根據(jù)結(jié)果來刷新各控件狀態(tài)即可:
這樣一來,即使后面需要增加更多控件,或增加邏輯參數(shù),都可以在這個(gè)方法里統(tǒng)一處理,然后在需要刷新頁面的地方調(diào)用,而我們不需要關(guān)心具體操作發(fā)生時(shí)頁面的上一個(gè)狀態(tài)。到這里,業(yè)務(wù)方法就大功告成了,我們保證了在任意操作流程中交互的狀態(tài)都是可唯一確定的。
OK 下一步,邏輯表達(dá)式要怎么做呢?
3、卡諾圖簡介
卡諾圖[2]可以用于表示和化簡邏輯函數(shù)。
一個(gè)邏輯函數(shù)的卡諾圖,就是將此函數(shù)的最小項(xiàng)表達(dá)式中的各最小項(xiàng)填入相應(yīng)的特定方格圖內(nèi),這樣的方格圖就是卡諾圖。
舉例,比如 4變量的卡諾圖,記ABCD?為所用4個(gè)變量,行與列頭為4個(gè)變量分別對(duì)應(yīng)的取值(true 或 false,對(duì)應(yīng)記為邏輯 1 或 0 方便計(jì)算),16個(gè)方格中相鄰的數(shù)字0~15依順序代表方格邏輯相鄰:
圖3.1 卡諾圖邏輯相鄰格式
3.1 代數(shù)含義
一個(gè)邏輯函數(shù),如果有 n 個(gè)變量,則有$$2^n$$個(gè)最小項(xiàng),最小項(xiàng)為所有所有變量的積,也就是所有變量的與門邏輯。
3.2 特點(diǎn)
- 邏輯函數(shù)有幾個(gè)變量,就有幾個(gè)因子
- 每個(gè)變量都是它的一個(gè)因子
- 每一變量或以原變量形式出現(xiàn)(A、B、C)?,或以非變量形式出現(xiàn)(!A、!B、!C)
- 每個(gè)乘積的組合僅出現(xiàn)一次,且取值為1
- 任何邏輯函數(shù)都可以轉(zhuǎn)換成最小項(xiàng)的形式
3.3 相鄰組合
任何一對(duì)相鄰最小項(xiàng)可以組合為比原最小項(xiàng)本身少一個(gè)變量的單項(xiàng)。
3.4 邏輯相鄰
- 最上面的一列和最下面的一列邏輯相鄰,可以相互化簡
- 最左邊一列和最右邊的一列邏輯相鄰,可以相互化簡
- 四個(gè)角邏輯相鄰,可以相互化簡
- 要更好地理解上述規(guī)則和邏輯相鄰,我們需要使用格雷碼。
4、格雷碼編碼規(guī)則
4.1 格雷碼原理
畫卡諾圖的時(shí)候需要先將所有變量可能以格雷碼的形式排列在方格兩側(cè),所有變量有$$2^n$$個(gè),格雷碼的基本特點(diǎn)就是任意兩個(gè)相鄰的代碼只有一位二進(jìn)制數(shù)不同,主要用于在數(shù)字電路中變化時(shí)每次就只有一位發(fā)生變化,用以提高電路的穩(wěn)定性[3]。
十進(jìn)制數(shù) | 二進(jìn)制數(shù) | 格雷碼 | 十進(jìn)制數(shù) | 二進(jìn)制數(shù) | 格雷碼 | |
0 | 0000 | 0000 | 8 | 1000 | 1100 | |
1 | 0001 | 0001 | 9 | 1001 | 1101 | |
2 | 0010 | 0011 | 10 | 1010 | 1111 | |
3 | 0011 | 0010 | 11 | 1011 | 1110 | |
4 | 0100 | 0110 | 12 | 1100 | 1010 | |
5 | 0101 | 0111 | 13 | 1101 | 1011 | |
6 | 0110 | 0101 | 14 | 1110 | 1001 | |
7 | 0111 | 0100 | 15 | 1111 | 1000 |
表3.1 格雷碼編碼規(guī)則
4.2 格雷碼規(guī)則
自然二進(jìn)制數(shù)到格雷碼:保留二進(jìn)制碼的最高位作為格雷碼的最高位,而次高位格雷碼為二進(jìn)制碼的高位與次高位相異或,而格雷碼其余各位與次高位的求法相類似。
格雷碼到自然二進(jìn)制數(shù):保留格雷碼的最高位作為自然二進(jìn)制碼的最高位,而次高位自然二進(jìn)制碼為高位自然二進(jìn)制碼與次高位格雷碼做相異或計(jì)算,而自然二進(jìn)制碼的其余各位與次高位自然二進(jìn)制碼的求法相類似。
以一個(gè)四位二進(jìn)制數(shù)來舉例,二進(jìn)制(abcd),依據(jù)規(guī)則轉(zhuǎn)換為格雷碼就是
即異或計(jì)算【a, (a^b), (b^c), (c^d)】, 依據(jù)規(guī)則繼續(xù)轉(zhuǎn)化二進(jìn)制的話就是 【a, (a^a^b), (a^a^b^b^c), (a^a^b^b^c^c^d)】,化簡之后仍然可以得到(abcd)。
5、卡諾圖簡單邏輯化簡
5.1 化簡方法
邏輯化簡的實(shí)際目標(biāo)是盡可能地減少表達(dá)式中包含的項(xiàng)數(shù)以及各項(xiàng)包含的變量數(shù)[4]。下圖為三變量卡諾圖結(jié)構(gòu),m0~m7表示變量ABC的8種狀態(tài)[7]。
圖5.1 三變量卡諾圖
此圖即為基本卡諾圖的形式,兩側(cè)變量依據(jù)格雷碼形式,目的就是畫卡諾圈時(shí)要將里面的 1 全都包括在內(nèi)[5]。
類似的,有4變量卡諾圖描述16種狀態(tài),其結(jié)構(gòu)如下所示:
圖5.2 四變量卡諾圖
卡諾圖填寫完成后,就可以作卡諾圈了,通過圈選與合并狀態(tài),我們可以將邏輯多項(xiàng)式化簡得到其最小項(xiàng)表達(dá)式。
5.2 卡諾圈原則
卡諾圈原則:所作卡諾圈盡量大,卡諾圈的數(shù)量盡量少
- 卡諾圖上處在相鄰、相對(duì)、相重位置的小方格所代表的最小項(xiàng)為相鄰最小項(xiàng)。
- 兩個(gè)小方格相鄰, 或處于某行(列)兩端時(shí),所代表的最小項(xiàng)可以合并,合并后可消去一個(gè)變量。
- 四個(gè)小方格組成一個(gè)大方格、或組成一行(列)、或處于相鄰兩行(列)的兩端、或處于四角時(shí),所的表的最小項(xiàng)可以合并,合并后可消去兩個(gè)變量。
- 八個(gè)小方格組成一個(gè)大方格、或組成相鄰的兩行(列)、或處于兩個(gè)邊行(列)時(shí),所代表的最小項(xiàng)可以合并,合并后可消去三個(gè)變量。
- 對(duì)于方格中帶有未知變量x的,是可圈可不圈的,依據(jù)自己實(shí)際情況而定[6]。
5.3 化簡舉例與步驟
用上面拍攝頁的例子,我們?cè)趺从媚菐讉€(gè)變量,得到最終的交互結(jié)果呢?一起按步驟一步步來看。
5.3.1 抽出變量
各變量已有對(duì)應(yīng)的取值方法,為方便使用變量,我們計(jì)算中用ABC符號(hào)來代表各參數(shù),比如 A 代表是否已錄視頻,取0為false,1為true;其他變量同理,可寫出:
然后拿出需要計(jì)算的控件,先用一個(gè)邏輯比較簡單的,比如拍攝鍵 takeButton? ,然后把與之相關(guān)的變量找出來,按照業(yè)務(wù)要求得知,它的顯示與隱藏只和“是否有視頻”、“是否填充子特效”這兩個(gè)參數(shù)有關(guān),當(dāng)然你也可以把看似相關(guān)的其他參數(shù)帶進(jìn)去,在化簡完成后,無關(guān)參數(shù)最終會(huì)被消去。
5.3.2 填充卡諾圖
那么,與拍攝鍵相關(guān)的變量就是 hasVideo,hasSubEffectPhoto? ,對(duì)應(yīng)符號(hào)是 A,D ,分別取0和1值。在下圖中,A為行,B為列,填充到2變量的卡諾圖中:
圖5.3 初始化卡諾圖
其中行代表A的取值,列為B的取值情況,它們相交處共同描述了AB全部4種取值:00,01,10,11。
然后,對(duì)應(yīng)每一種取值情況,我們需要思考 拍攝鍵 takeButton? 的顯示狀態(tài),并在相應(yīng)空格里填入0或1,含義由我們來定,這里取0為隱藏,1為顯示較直觀,那么有:
A = 0,B = 0 ?-->無視頻 & 無填充子特效時(shí),拍攝鍵要隱藏,所以取0,則在坐標(biāo)(0,0)處填0;
A = 0,B = 1 ?-->無視頻 & 有填充子特效時(shí),拍攝鍵要顯示,所以取1,則在坐標(biāo)(0,1)處填1;
A = 1,B = 0 ?-->有視頻 & 無填充子特效時(shí),拍攝鍵要顯示,所以取1,則在坐標(biāo)(1,0)處填1;
A = 1,B = 1 ?-->有視頻 & 有填充子特效時(shí),拍攝鍵要顯示,所以取1,則在坐標(biāo)(1,1)處填1;
圖5.4 填寫狀態(tài)后的卡諾圖
5.3.3 畫卡諾圈
根據(jù)上面2.4邏輯相鄰的最小項(xiàng)原則和4.1提到的畫圈原則,把相鄰的 1 圈起來,得到全部的卡諾圈:
圖5.5 畫出卡諾圈
這個(gè)圖里我們得到2個(gè)卡諾圈,全部卡諾圈表達(dá)式相加,對(duì)應(yīng)寫成邏輯式即得:
A + B
已是最簡表達(dá)式,再把符號(hào)AB再換回代碼中的變量,有:
因?yàn)榇a中使用的是 .isHidden?屬性,只要把所得表達(dá)式再取反即有 !(A+B),寫為代碼的邏輯式就是:
至此我們就得到了這個(gè)控件的狀態(tài)表達(dá)式,在任何時(shí)候調(diào)用這個(gè)刷新方法,就只依賴參數(shù)做顯示。
5.3.4 四變量卡諾圖舉例
你可能覺得,上面的變量就兩個(gè),我自己列舉一下也可寫出表達(dá)式,不用走卡諾圖。是的恭喜你已發(fā)現(xiàn)這個(gè)規(guī)律,一般2變量我們可以輕易handle,直接計(jì)算可能會(huì)比畫圖來的簡單。但通過這個(gè)做法我們了解其原理與概念之后,現(xiàn)在一起來看個(gè)稍微復(fù)雜些的,4變量場景的表達(dá)式是如何計(jì)算的。
就用 特效浮層鍵 的交互狀態(tài)來試試吧,對(duì)應(yīng)圖1.1中屏幕左下方那個(gè)半透明白色圓形的按鍵,在就緒狀態(tài)或視頻暫停狀態(tài)下它會(huì)出現(xiàn)在拍攝鍵左側(cè):
圖5.6 特效浮層按鍵示意
同樣先來看下計(jì)算后的最終結(jié)果:
思考:它在什么情況下需要顯示或隱藏呢?由業(yè)務(wù)要求[1]可知:是否錄視頻,是否有特效、子特效,是否拍了子特效照片,這幾個(gè)參數(shù)就能決定其狀態(tài)。
于是你問,那音樂參數(shù)F呢?我們通過研究具體需求[1]得知,無論有無音樂,都不會(huì)影響它的顯示,因此F是個(gè)無關(guān)參數(shù),計(jì)算時(shí)不用考慮。當(dāng)然,你非要把它加進(jìn)來也行,因?yàn)檫壿嬍交喓螅瑹o關(guān)參數(shù)都會(huì)被消去,不影響結(jié)果,這也是“最小項(xiàng)”這個(gè)名字的由來:計(jì)算出最少相關(guān)的參數(shù)。要知道,參數(shù)越少就越方便我們化簡邏輯式,所以那些一眼看去就無關(guān)的參數(shù)可以不用加進(jìn)來。若是計(jì)算后發(fā)現(xiàn)我們少帶了某個(gè)參數(shù)或業(yè)務(wù)要求變化了,則再把它加進(jìn)來重新計(jì)算表達(dá)式即可。
- 確定參數(shù)
綜上,我們所需參數(shù)為ABCD:
畫出4參數(shù)卡諾圖框架:
其中AB兩個(gè)變量作為列寫在一起,CD兩個(gè)作為行寫在一起,變量的順序不是一定的,你也可以換著寫,但格雷碼0和1的位置在表頭是固定的,且最終計(jì)算結(jié)果也是一樣的。
AB列中,00代表AB取值 A=false; B=false?,01代表取值 A=false; B=true,依此類推。
于是每個(gè)格子就對(duì)應(yīng)一個(gè)狀態(tài),比如第0行第2列,ABCD取值為0011,代表A=false; B=false; C =true; D=true 這個(gè)狀態(tài)。所以4變量卡諾圖可以把這些變量全排列的16個(gè)狀態(tài)都表示出來,不會(huì)漏掉某個(gè)狀態(tài)。
然后對(duì)于每個(gè)參數(shù)狀態(tài),我們思考目標(biāo)控件的顯示狀態(tài)。這里為方便配合使用屬性 .isHidden?,我們定義邏輯填入1為需要隱藏,0為不隱藏?。注意這里與上面例子2變量里的顯示隱藏定義是反相的。參數(shù)含義與格子對(duì)應(yīng),比如,在0011狀態(tài)時(shí),代表狀態(tài)含義是:
0011 = 無錄視頻,無特效,有子特效,子特效已拍照
本例有個(gè)特殊點(diǎn),因?yàn)樵谛枨筮壿嬌希瑓?shù)B“無特效”比CD有更高優(yōu)先級(jí):即無特效時(shí)不可能有子特效,也不可能給子特效拍照,所以綜合考慮,在狀態(tài)0011時(shí)需要顯示控件,即不隱藏,則在0011對(duì)應(yīng)格子里填入0。
- 填充卡諾圖
按照上述方法,把全部16個(gè)格子都填上對(duì)應(yīng)(控件需要隱藏)的狀態(tài),AB為列,CD為行:
- 按前面 4.2卡諾圈原則 作出全部的卡諾圈,把所有的 1 圈起來:
- 化簡
根據(jù)卡諾圈寫出邏輯表達(dá)式并化簡為最小項(xiàng)表達(dá)式(為方便理解,卡諾圈與其表達(dá)式用對(duì)應(yīng)的顏色):
再把符號(hào)換回代碼中的變量,即有:
至此,我們就把變量的邏輯狀態(tài)與特效按鍵的狀態(tài)對(duì)應(yīng)起來了。
使用此方法的優(yōu)勢在于:若是需求有變需要更改狀態(tài),則只需要列一遍參數(shù),重新畫卡諾圖計(jì)算表達(dá)式即可,修改的地方也只有這一行的邏輯式,而不會(huì)影響其他控件的邏輯,也不用再走一遍改動(dòng)后的業(yè)務(wù)流程。
6、拓展:五變量卡諾圖
五變量以下最多十六方格,也可用上述方法解出得到。但在實(shí)際開發(fā)中極少需要到5變量,掌握4變量方法已足夠應(yīng)對(duì)大多數(shù)場景。此處僅作拓展了解。六變量以上方格過多,用此方法反倒麻煩[3]。
圖6.1 五變量卡諾圖
它是由四變量最小項(xiàng)圖構(gòu)成的,將左邊的一個(gè)四變量卡諾圖按軸翻轉(zhuǎn) 180 °而成。左邊的一個(gè)四變量最小項(xiàng)圖對(duì)應(yīng)變量 E =0 ,軸左側(cè)的一個(gè)對(duì)應(yīng) E =1 。
這樣一來除了幾何位置相鄰的小方格滿足鄰接條件外,以軸對(duì)稱的小方格也滿足鄰接條件,這一點(diǎn)需要注意。圖中最小項(xiàng)編號(hào)按變量高低位的順序?yàn)?nbsp;EABCD 排列時(shí),所對(duì)應(yīng)的二進(jìn)制碼確定。
此時(shí)要注意列上變量排列的左右對(duì)稱關(guān)系,對(duì)于既不含 E非也不含 E 的與項(xiàng),可以填入 E非四變量卡諾圖中然后以中間軸翻轉(zhuǎn) 180 °,在 E 四變量卡諾圖中對(duì)稱位置也填上“ 1 ”。
五變量邏輯式化簡的舉例說明如下,每個(gè)步驟原理在上文已作詳盡說明,此處不再贅述:
化簡下式:
- 填入卡諾圖:
- 作卡諾圈:
合并與化簡得:
7、小結(jié)
我們簡要介紹了卡諾圖原理與其化簡方法,這個(gè)工具和思想可以用在任何多參數(shù)有競爭或多種情況的場景下決定某個(gè)操作是否執(zhí)行。這個(gè)方法在參數(shù)較多且狀態(tài)復(fù)雜時(shí)使用,若邏輯狀態(tài)較簡單,則可直接用表達(dá)式寫出,代碼邏輯力求更清晰明了。
在上述場景的操作流程中,任何時(shí)候調(diào)用這個(gè)刷新方法,我們都可獲得符合當(dāng)下參數(shù)的頁面狀態(tài),因?yàn)榻换ゾ椭灰蕾噮?shù)做顯示,而不需要考慮其前置狀態(tài)。
卡諾圖邏輯化簡法優(yōu)點(diǎn)有:簡化了多參數(shù)多控件等復(fù)雜情況下邏輯與方法難以直觀處理的情況,且在后續(xù)維護(hù)迭代中,也可獨(dú)立地修改某個(gè)控件的刷新邏輯,不用擔(dān)心影響其他控件或業(yè)務(wù)流程,每個(gè)交互的控件狀態(tài)修改簡易靈活,方便計(jì)算。
同時(shí),卡諾圖的使用也有其局限性,它比較適合4變量或以下的場景,在5變量及以上用此方法反而復(fù)雜,且在實(shí)際開發(fā)中,4變量場景已然是比較少見,則此法已足夠我們處理大多數(shù)2~4變量的交互邏輯情況了。
Reference
[1] https://blog.shizhuang-inc.com/article/Nzc4Ng==
[2] https://blog.csdn.net/wangqinyi574110/article/details/116573015
[3] https://www.cnblogs.com/uiojhi/p/7517732.html
[4] https://zhuanlan.zhihu.com/p/158535749
[5] https://www.cnblogs.com/iBoundary/p/11303861.html
[6] https://www.pudn.com/news/6367746ba4b7e43a5e898044.html
[7] https://zhuanlan.zhihu.com/p/268750530