這是一個業(yè)務(wù)上遇到的真實場景。
我們定義了一個配置文件格式,給機器資源分類。
寫出來大概是這個樣子
GroupA: MachineA, MachineB, MachineC
GroupB: MachineD, MachineE
GroupC: MachineA, MachineC
GroupD: GroupB & GroupC
......
總結(jié)一下, 有如下幾個規(guī)則:
- Group的名字和Machine的名字都由用戶自己指定
- Group的描述可以是一組機器(見上圖GroupA, GroupB, GroupC), 也可以是其它Group的運算表達(dá)式(見上圖GroupD)
- 表達(dá)式支持'&', '|', '-' 三種運算符, 分別代表集合運算中的交集,并集,差集
- 表達(dá)式不能包含括號, 計算的時候按照從左到右的順序
問題來了, 當(dāng)我們拿到這么一份配置文件的時候,需要知道每個Group包含多少機器,請問如何編碼實現(xiàn)?
這個問題乍一看很簡單,如果Group的描述本身已經(jīng)是機器組,直接計算Machine的數(shù)量即可。 如果Group的描述是表達(dá)式, 則把表達(dá)式中出現(xiàn)的Group用機器組替換一下,再求數(shù)量也行啊。 難點在哪呢?
關(guān)鍵就在替換這里, 我們看下面一個場景
GroupA: GroupB & GroupC
GroupB: GroupD | GroupE
GroupC: MachineA, MachineB
GroupD: GroupA & GroupE
GroupE: MachineC, MachineD
讀者朋友可以自己試一試用代換法求解GroupA, 然后很快就會發(fā)現(xiàn)"臣妾做不到啊",原來, A引用了B,B引用了D, D又引用了A, 形成了死循環(huán)。 也就是說這個配置文件本身就是錯誤的, 但是如果我們的代碼不能檢測到這種錯誤,就會導(dǎo)致因為用戶的錯誤配置造成系統(tǒng)死循環(huán), 多么可怕啊。
怎么檢測死循環(huán)呢, 其實也不難, 仔細(xì)想一想,這其實就是一個有向圖環(huán)檢測問題(如果不理解,可以參考筆者的另一篇文章--業(yè)務(wù)模型抽象成有向圖環(huán)檢測算法,模型和這個很像)。
這樣做是解決問題了,但是算法寫起來好復(fù)雜,有沒有簡單點的方法呢?
其實筆者當(dāng)初實現(xiàn)的時候也是按照上述的方法解決的,但有一天整理這段代碼時發(fā)現(xiàn)了,根本不用這么復(fù)雜好嘛!轉(zhuǎn)換一下思路, 調(diào)整一下展開表達(dá)式的順序就解決了, 解法如下:
- 遍歷所有的Group, 把所有只需要一層展開的表達(dá)式 轉(zhuǎn)化成 Machine List(一層展開指的是表達(dá)式中引用的Group均為確定的Machine List)
- 重復(fù)步驟1,如果在整個遍歷過程中,沒有新的表達(dá)式被展開, 說明遇到了死循環(huán),流程終止。 如果所有的表達(dá)式都被展開, 說明問題解決。
是不是變簡單了,這種做法連死循環(huán)都不需要檢測了。其實,事后想一想,這算法并沒有什么難度(甚至小學(xué)生都會,因為這就是數(shù)學(xué)中的多元一次方程啊),只是在一種思維遇到困難的時候,我們往往可以跳出思維定式,找到簡潔之道。