底層結構

做者:Soroush Khanlou,原文連接,原文日期:2017-01-12
譯者:Cwift;校對:walkingway;定稿:CMBgit

我常常觀察一個類型的實例變量,這樣我就能夠更深刻地理解這個類型設計的初衷。一旦你知曉該類型的底層結構,它的用法也就隨之浮出水面了。反之亦然:若是你沒看過一個對象內部成員的佈局狀況,那麼不可能準確把握該對象的功能。這種狀況對於蘋果的閉源類型尤爲明顯。github

一個很好的例子是 NSDate 類型。當我開始編程時,就試着去了解如何使用 NSDate 以及它全部的兄弟對象,好比 NSDateComponentsNSDateFormatter 以及 NSCalendar,那真是一段艱難的歲月。爲何你須要使用 NSCalendar 在本來的日期上增長兩天?這些類之間的邊界劃分讓人捉摸不定,這使得當你想要尋找某些特定的功能時,沒法準肯定位到某個具體的對象中。編程

對我來講,關鍵的啓示是理解 NSDate 在底層的真實面目,是什麼緣由使得部分功能散落到其餘類中。NSDate 只是一個花哨的包裝器。僅此而已,文檔也揭示了這一事實:swift

NSDate 對象封裝了單個的時間點,獨立於任何特定的日曆系統或者時區。數組

全部的 NSDate 都存儲了一個浮點數,這個浮點數表明了從 2001 年 1 月 1 日 00:00:00 UTC 起的秒數。這些秒數與時區、星期幾、月份、夏令時、閏秒或者閏年一點關係都沒有。若是所需的計算基於秒數就能夠完成,那麼它會在 NSDate 上進行。不然,就要藉助其餘的類型了。promise

列舉一下單純依靠這個浮點數能作的操做:比較(earlierDatelaterDate)、判斷相等以及計算時間間隔(依舊返回一個浮點數)。distantFuturedistantPast 也是顯而易見的,它們是以面向將來和過去兩個維度來計算出指望的時間(浮點數表示)。安全

對於其餘功能,你必須使用其餘的類和對象。例如,要及時地向一個時刻中增長一天的時間,能夠選擇向一個 NSDate 中增長 24*60*60 秒的方式,不過最好的方式是經過 NSCalendar 來操做,避免遇到夏令時間、閏秒/天的問題 ,以及其餘可能隨時間出現的非標準問題。這篇博客介紹了使用 NSCalendar 進行這些計算的狀況。佈局

由於 NSDate 不存儲日期中與咱們所指望的月份相關的任何信息,若是要更改該月份,則必須使用一個瞭解狀況而且可以把日期拆分紅各個「組件」的對象。爲此,咱們要用到 NSDateComponents,看看你可否弄懂它內部存儲數據的方式。atom

當我在編寫我本身的 Promise 庫時,發現了另外一個有趣的例子,經過研究一個對象存儲屬性的佈局來了解該對象的性質。若是查看每一個 Promise 對象的存儲屬性,你會看到三樣東西:spa

public final class Promise<Value> {
    
    private var state: State<Value>
    private let lockQueue = DispatchQueue(label: "promise_lock_queue", qos: .userInitiated)
    private var callbacks: [Callback<Value>] = []

每一個 promise 都有它的當前狀態(如 .pending.fulfilled 或者 .rejected),一個確保線程安全的隊列,以及當 promise 完成時或者被拒絕時調用的回調數組。

當我寫完這個庫時,看了一些 Signal/Observable 的實現,看看可否理解它們。我發現 JensRavens/Interstellar 的實現是最直接的。我查看了這個庫中每一個 Signal 對象的實例屬性,發現了一個很是類似的結構:

public final class Signal<T> {
    
    private var value: Result<T>?
    private var callbacks: [Result<T> -> Void] = []
    private let mutex = Mutex()

它包含了存儲當前狀態的部分,存儲回調的部分以及存儲線程安全原語的部分。順序有些不一樣,他們使用了互斥體而不是隊列,但原理是相同的。這兩種類型之間的惟一區別是語義上的:promises 能夠在完成時清除它們的回調(釋放本身以及捕獲的變量),而 signals 必須保持它們的回調。

我認爲這個原則也能夠幫助設計本身的類型。看看你正在處理的對象的屬性。每個屬性都有目的性嗎?它是否對該對象的總體特性有幫助?是否有些屬性在該對象的一些實例中可以用到,而在另外一些實例中用不到?若是是的話,這些屬性可能屬於其餘對象。確保類型的實例變量被嚴格控制而且充分利用,確保咱們的每個對象在應用中都有着明確的定位。

本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg

相關文章
相關標籤/搜索