在程式開發中,我們總是希望能夠更加簡潔、更加語義化地去表達自己的邏輯,鏈式呼叫是一種常見的處理方式。我們常用的 masonry、 expecta 等第三方庫就採用了這種處理方式。
像這種用於特定領域的表達方式,我們叫做 dsl (domain specific language),本文就介紹一下如何實現乙個鏈式呼叫的 dsl.
我們舉乙個具體的例子,比如我們用鏈式表示式來建立乙個 uiview,設定其 frame、backgroundcolor, 並新增至某個父 view。
對於最基本的 objective-c (在 ios4 block 出現之前),如果要實現鏈式呼叫,只能是這個樣子的:
鏈式呼叫可以用兩種方式來實現:
在返回值中使用屬性來儲存方法中的資訊
比如,masonry 中的.left .right .top .bottom
等方法,呼叫時會返回乙個masconstraintmaker
類的例項,裡面有left/right/top/bottom
等屬性來儲存每次呼叫時的資訊;
再比如,expecta 中的方法.notto
方法會返回乙個expexpect
類的例項,裡面有個 bool 屬性self.negative
來記錄是否呼叫了.notto
;
再比如,上例中的 .with 方法,我們可以直接return self;
使用 block 型別的屬性來接受引數
比如 masonry 中的.offset(15)
方法,接收乙個 cgfloat 作為引數,可以在masconstraintmaker
類中新增乙個 block 型別的屬性:
比如例子中的.position(x, y)
,可以給的某類中新增乙個屬性:
在呼叫.position(x, y)
方法時,執行這個block,返回 viewmaker 的例項保證鏈式呼叫得以進行。
從語義層面上,需要界定哪些是助詞,哪些是需要接受引數的。為了保證鏈式呼叫能夠完成,需要考慮傳入什麼,返回什麼。
還是以上面的例子來講:position
size
bgcolor
這些。
下面我們分別從四段來看,如何實現這樣乙個表示式:
(1) 賓語
在 alloca(uiview) 的語義中,我們確定了賓語是 a uiview。由於確定 uiview 是在 intoview 截止那時,所以我們需要建立乙個中間類來儲存所有的中間條件,這裡我們用 viewmaker 類。
另外我們可以注意到alloca是乙個函式,而uiview無法直接傳遞到這個函式中,語法就要變成alloca([uiview class])
而失去了簡潔性。所以我們需要先定義乙個巨集來「吞」掉中括號和class
這個方法:
(2) 助詞
很多時候,為了讓 dsl 的語法看起來更加連貫,我們需要一些助詞來幫助,例如 masonry 裡面的 make.top.equalto(superview.mas_top).with.offset(padding.top) 這句中的 with 就是這樣乙個助詞。
而這個助詞和我們學過的語法一樣,通常沒有什麼實際效果,簡單返回self就可以。
需要注意的是,返回自己,就沒有辦法阻止使用者不斷呼叫自己.with.with.with
,為了避免這種情況,可以新生成乙個類,每個類都擁有自己所在層次的方法,避免躍層呼叫。
這樣就有效防止了,.with.with.with
這樣的語法。但是實際上,我們要根據真實的需要來進行開發,使用 dsl 的使用者是為了更好的表達性,所以並不會寫出.with.with.with
這樣的**,這樣的防護性措施就顯得有點不必要了。
不過使用類來區分助詞還有另外幾個小好處,就是它可以確保在語法提示的時候,viewclasshelper
這個類只有.with
這樣乙個語法提示,而viewmaker
不出現.with
語法提示;並且同時確保.with
一定要出現。
(3) 修飾部分——定語
像例子中的position
size
bgcolor
這些都是定語部分,用來修飾uiview,他們以屬性的形勢存在於viewmaker
的例項中,為了支援鏈式表達,所以實現的時候,都會繼續返回self
。
我們來試著實現下:
(4) 終結詞
「終結詞」這個實在是在現代語法裡面找不到對應關係了,但是在 dsl 中,這一段尤為重要。viewmaker
的例項從頭至尾收集了很多的修飾,需要最後的乙個表達詞語來產生最後的結果,這裡就稱為」終結詞」。例如在 expecta 這個開源庫裡面的equal
就是把真正的行為表現出來的時候,to
和notto
都不會真正觸發行為。
在我們的例子裡,終結詞.intoview(asuperviwe)
可以這樣實現:
這樣,乙個終結詞就寫好了。
最終**的彙總:
這種鏈式呼叫能夠使程式更加清晰,在特定場景下使程式的可讀性更強。這種手段在swift也是相同道理,大家可以善加利用,讓自己的**更加美觀。
攻擊者是如何利用「隱寫技術」的?
據稱,在不久的將來,隱寫技術將越來越多地用於攻擊中。那麼,攻擊者如何使用隱寫術,以及企業應該如何抵禦基於隱寫術的攻擊?nick lewis 隱寫術是指在普通郵件中隱藏秘密訊息的技術。通過使用隱寫術 例如加密技術 攻擊者可儘量減少他們的攻擊被發現的機會。但與加密一樣,有效使用隱寫技術也需要正確的部署。...
python函式如何寫 python如何寫函式
python函式的定義 定義函式,也就是建立乙個函式,可以理解為建立乙個具有某些用途的工具。定義函式需要用 def 關鍵字實現,具體的語法格式如下 def 函式名 形參列表 由零條到多條可執行語句組成的 塊 return 返回值 其中,用 括起來的為可選擇部分,即可以使用,也可以省略。此格式中,各部...
python如何寫日誌 python如何寫日誌
這篇文章介紹了 python 的 logging 模組,包括它的設計以及針對更多複雜案例的適用方法。這篇文章不是寫給開發者的文件,它更像是乙個指導手冊,來說明 python 的 logging 模板是如何搭建的,並且激發感興趣的人深入研究。為什麼使用 logging 模組?也許會有開發者會問,為什麼...