操做抽象設計-實踐

轉發;https://www.jianshu.com/p/bc05e9ff203f安全


操做抽象多線程

咱們要怎麼實現前面所提到的操做抽象呢?實際上Cocoa中已經存在這種帶有狀態的操做抽象了,NSOperation。看到這裏你可能想說,早說NSOperation不就好了,扯這麼多幹嗎。前面的分析與設計是不針對任何具體實現的,純粹用抽象概念來討論的,如今到了實現階段,纔去考慮前面整個的設計要怎麼實現,用什麼來實現的。分析設計和實現這兩個過程是不能反過來的,也就是不能由於想用NSOperation再去設計使用場景。例如,你要吃麪,因此你須要一雙筷子,而不是你有一雙筷子,因此你要吃麪。併發

在考慮具體實現時,咱們會找現有的框架或過往的實現中是否存在相同的對象模型,若是有現成的對象模型,那麼會優先選擇用現成的對象模型而不是作一個新的對象模型,這並非爲了偷懶,理由很簡單,由於現成的對象模型是通過實踐和測試的,是相對穩定的,沒有一個對象模型是一創造出來就能夠穩定應對全部場景的,都要通過長期地應用,維護和擴展才會變得相對穩定的,因此優先選擇如今的對象模型,若是沒有現成的對象模型纔會去創造一個。app

NSOperation的內部實現框架

看到NSOperation和NSOperationQueue,可能不少人的第一反應是多線程,NSOperation與NSOperationQueue結合實現了多線程技術,但多線程技術僅僅只是它們的一部份,並且在我看來,多線程技術並非NSOperation和NSOperationQueue的核心。在iOS4之後,NSOperation和NSOperationQueue的多線程是用GCD來實現的,也就是NSOperation與NSOperationQueue做爲GCD的面向對象的抽象物而存在。但若是你只是想以面向對象的方式來使用GCD,你本身實現Operation和OperationQueue的抽象,也不過四五百行代碼,並且效率要比Cocoa自帶的NSOperation和NSOperationQueue高,首先來了解一下NSOperation的內部實現。學習

顧名思義,NSOperationInternal是NSOperation的內部抽象,向NSOperation對象發送的消息最終都會轉發給內部的NSOperationInternal對象,NSOperationInternal對象完成具體的工做,也就是說咱們日常所用的NSOperation實際上只是一個代理,此代理(Proxy)非彼代理(Delegate)。NSOperationInternal的內部結構大體是怎樣的?
測試

NSOperationInternal內部結構中的queue是NSOperation被添加的queue,operation是外部的NSOperation對象,dependencies是NSOperation的關聯對象,down_dependencies也就是NSOperation的反關聯對象了,state是NSOperationInternal對象目前處理事件的狀態,這跟NSOperation不一樣,NSOperation是用幾個BOOL值(isFinished,isExecuting,isReady)來表示事件當前狀態的。ui

NSOperation被添加到NSOperationQueue的過程是怎樣的?spa

當NSOperation被添加到相應的NSOperationQueue時,NSOperation的NSOperationInternal就會把queue設置爲當前的NSOperationQueue。線程

設置NSOperation對象之間的依賴關係的過程又是怎樣的?

當設置NSOperation1與NSOperation2的依賴關係後,NSOperation2被添加到了NSOperationInternal1的dependencies中,NSOperationInternal1被添加到了NSOperationInternal2的down_dependencies中,而後NSOperationInternal1設置NSOperation1的isReady狀態爲NO。

NSOperationInternal除了完成NSOperation的具體工做外,它還有一個職責就是監聽NSOperation的狀態(isFinished,isExecuting,isReady)。當NSOperation的狀態改變時,NSOperationInternal會做出不一樣的響應。當NSOperation2處理完事件後,NSOperation1是如何得知且開始處理本身的事件?

因爲NSOperation被添加到NSOperationQueue時,NSOperation的NSOperationInternal會把queue設置爲當前的NSOperationQueue,因此NSOperation的isReady狀態從NO變成YES,即表示NSOperation能夠處理事件,NSOperationInternal監聽到NSOperation狀態變化時,NSOperationInternal會向queue發送啓動相應的NSOperation的消息。這就是NSOperation能夠自動化的緣由,要注意的是,NSOperation要跟NSOperationQueue結合才能實現自動化,若是隻是設置了NSOperation之間的依賴關係,但沒有把NSOperation添加到NSOperationQueue中,NSOperation是不會自動化的。

NSOperationInternal經過監聽NSOperation的狀態來完成相應的操做,因此當咱們自定義NSOperation的子類時須要手動管理NSOperation的isFinished,isExecuting狀態。當咱們自定義NSOperation的子類時,要麼實現start方法,要麼實現main方法,若是兩個方法同時實現,那麼只有start方法會被調用。

爲了實現NSOperation的自動化,Cocoa爲NSOperation增長了NSOperationInternal,讓NSOperationInternal在背後處理一切事務。若是NSOperation只用於多線程技術,那麼它的狀態機制就沒有太多意義了。因此當你只是想以面向對象的方式來使用GCD,本身實現的效率會更高。

操做管理抽象

咱們能夠用NSOperation來實現操做抽象(Operation),那麼操做管理抽象(OperationManager)又怎麼來實現呢?實現操做管理抽象須要考慮哪些問題?

實現操做管理抽象至少要考慮如下問題,是否爲每一類操做抽象都建立一個相應的操做管理抽象?若是不爲每一類操做抽象配置一個相應的操做管理抽象,那用什麼來讓每一類操做抽象保持獨立性?NSOperation須要跟NSOperationQueue結合使用才能實現自動化,是否由操做管理抽象來建立和管理NSOperationQueue?不一樣類型的操做抽象是否能夠共用同一個NSOperationQueue?是否存在全局的NSOperationQueue?

操做抽象有什麼獨立性?相似Alert操做抽象須要一個接一個地處理,若是共用同一個操做管理抽象,那麼這個操做管理抽象的實現就會存在許多的判斷語句來區分不一樣類型的操做抽象,解決判斷語句多的問題,能夠選擇爲不一樣類型的操做抽象建立一個相應的配置抽象,經過配置抽象來提供獨立性,但這樣會使得操做管理抽象的實現愈來愈複雜,須要的抽象也愈來愈多,這對於之後的維護和擴展都不利,並且學習成本也大大地增長了。

若是NSOperationQueue由客戶建立,每個要用操做抽象的客戶都須要本身維護一個或多個NSOperationQueue,那麼客戶的職責就增長了,而咱們的初衷是減小客戶的交互。若是不一樣類型的操做抽象不能共用同一個NSOperationQueue,那麼就須要爲每一類操做抽象都建立並維護一個NSOperationQueue。

面對這些問題,咱們先作出一些假設,嘗試基於這些假設來實現操做管理抽象。每一類操做抽象都有一個相應的操做管理抽象,由操做管理抽象來建立和管理NSOperationQueue,不一樣類型的操做抽象能夠共用同一個NSOperationQueue,存在全局的NSOperationQueue。

考慮一下操做管理抽象的基本實現,基本實現就是建立NSOperationQueue,根據實際須要對每一類操做抽象作額外的處理,把操做抽象添加到NSOperationQueue中。如今對基本實現作通常化的抽象,建立一個高層抽象,在高層抽象定義一個基本實現的模板方法,由具體的操做管理抽象實現模板方法中相應的方法。

如今還有兩個需求要解決,不一樣類型的操做抽象能夠共用同一個NSOperationQueue,存在全局的NSOperationQueue。能夠爲高層抽象(OperationManager)的模板方法中的子方法提供默認實際來解決這兩個需求,也就是在高層抽象中提供全局公共的NSOperationQueue。這樣,具體的操做管理抽象能夠根據本身的須要選擇實現或不實現建立NSOperationQueue的方法,還能夠對相應的操做抽象作一些額外的處理。

基於前面的假設肯定了基本設計,如今來肯定實現基本設計的語言,不一樣的語言會有不一樣的特性,在最終實現時,能夠根據語言特性來作一些特殊的處理,或者選擇更容易實現設計的語言來實現。如今咱們須要爲每一類操做抽象都建立一個相應的操做管理抽象,這種一對一的關係是否很像Objective-C中的類對象和實例對象?在Objective-C的世界中,全部的東西都是對象,包括類,Objective-C中的類對象主要有兩個職責,一是提供建立實例用的原型模板,二是用於消息機制。用類對象來充當設計中的操做管理抽象,這樣在編寫代碼的時候,再也不須要引入新的類型,在運行時也能夠減小所須要的內存,減小程序中的抽象。

首先對NSOperation類對象作職責擴展,爲NSOperation添加一個分類,分類中定義一個模板方法。

NSOperation的子類能夠實現模板方法中的兩個子方法,第一個子方法是一個hook,讓子類有權決定是否繼續執行模板方法,若是子類想徹底接手操做對象的管理,只要實現方法並返回YES便可。提供公共的NSOperationQueue,同時也留出擴展的空間讓子類建立和管理本身的NSOperationQueue。

咱們還須要有一個對象來控制線程安全,把操做對象安全地分配到操做管理對象中。對NSOperationQueue類對象作職責擴展,讓NSOperationQueue的類對象來完成這些操做,選擇NSOperationQueue類對象的主要緣由是,減小程序中的抽象,並且平時的習慣也是建立操做對象,再把操做對象添加到NSOperationQueue中。

客戶只須要關注完成某一事件須要什麼操做,這些操做怎麼組合,不須要關注這些操做的實現,也不須要關注這些操做是否併發,這些對客戶都是透明的

  • 做者:Delpan

  • 連接:https://www.jianshu.com/p/bc05e9ff203f

相關文章
相關標籤/搜索