面向新手的雜談:Flyweight(續)
上次有人問兩條method extraction的簡單判斷原則
1. 這段代碼如果被抽取,那麼傳入的參數里是否需要包含回調函數?
2. 這段代碼如果被抽取,那麼執行後返回值是否只用簡單變數(int, bool, enum等),且不包含其他必須以傳址方式來給出計算結果的參數?
的理由,所以再寫一些展開來說一下
首先來看第一條:
假定我們有兩段代碼
Procedure A:#Part 1FuncA(param)#Part 2Procedure B:#Part 3FuncB(param)#Part 4
如果在這兩段中,我們有Part1和Part3相同,Part2和Part4相同,並且FuncA和FuncB的參數列表一致,那麼我們是否需要把整個部分提取出來作為一個單獨的method呢?比如說抽取之後變成這個樣子:
Procedure C: InputFunc#Part 1(3)InputFunc(param)#Part 2(4)
我們看到:在這裡,輸入的param實質上依賴的是part1(3)的執行結果,而FuncA和FuncB的執行,會影響後續Part2(4)的執行,因此,這裡實質上是一個順序不可變的 職責鏈模式(Chain of Responsibility Pattern)。而在這其中,如果我們把Part1(3)和Part2(4)單獨提取並且封裝為Func1和Func2的話,那麼原有的Procedure A和Procedure B會變成這個樣子:
Func1:#Part 1Func2:#Part 2Procedure A: Func1() FuncA(param) Func2()Procedure B: Func1() FuncB(param) Func2()
Procedure A和Procedure B很好的闡釋了在不同的場景下,我們應當以執行何種的職責鏈,而當他們被抽取之後,就變成了
Func1://Part 1Func2://Part 2Procedure C: InputFunc Func1() InputFunc(param) Func2()
職責鏈結構發生了破壞,因為InputFunc為未知,我們即無法明確指出在職責鏈裡面,InputFunc只能限定為有限的某個或者某幾個Methods,亦無法在維護的時候保證其他人不把擁有同樣參數列表結構,但不屬於原有職責鏈中的其他Method作為參數傳入,因此是一種擁有不可控風險及破壞代碼可讀性和可維護性的行為。
之後來看第二條,這種情況相對而言會更複雜一點
假定我們有代碼:
Procedure A input x,y:#Part 1return result as intProcedure B input x,y:#Part 2return result as stringProcedure C input x, y, ref z:#Part 3z = result_stringreturn result a int
且有A和C在相同x輸入時,return值相同,B和C在相同y值輸出時,z和B的return值相同。那麼在這種情況下,Part 3實質上為Part 1及Part 2:
我們可以看到,當一個函數包含了兩個返回值時,其本質是對兩個返回值分別進行了計算處理。對於輸入參數而言,即使x和y是高度相關的,但在最後生成返回值的過程中,我們必然可以找出其中不特定依賴某一個輸入參數的位置,否則的話,則Part 1和Part 2的代碼必然相同(可以思考一下為什麼)。
如果Part 1和Part 2是相同的代碼,那麼實質上,Procedure A和Procedure B是同一個函數對不同返回值類型的重載:
Procedure A input x,y:#Part 1return result as intProcedure B input x,y:#Part 1(2)return result as string
而如果Part 1和Part 2不同,那麼實質上這是兩段不同的代碼,我們只需要關心其中相同的部分,如
Procedure A input x,y:#Part 1.1#Part 1.2#Part 1.3#Part 1.4return result as intProcedure B input x,y:#Part 2.1#Part 2.2#Part 2.3#Part 2.4return result as string
可以看到,在這種情況下,Part 1和Part 2中的子代碼段中,如果出現了相同的部分,那麼實質上是回到了第一條所描述的職責鏈模型的情況,將整個Procedure A和Procedure B抽取合併為Procedure C等同於第一條所述的破壞職責鏈結構的情況。
因此這兩條基本原則實質上指向的是同一種情況的不同表現形式,即,在代碼抽取的過程中破壞了職責鏈模式結構,使得原有代碼架構發生了實質性的變化從而產生了包括可讀性障礙、可靠性下降等一系列的問題 @Ender
推薦閱讀:
※C++中關於跨平台中子線程式控制制的一些心得(2):用於線程的同步的Async容器
※面向新手的雜談:Flyweight