<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                在 Objective-C 的世界里面經常錯過的一個東西是抽象接口。接口(interface)這個詞通常指一個類的 `.h` 文件,但是它在 Java 程序員眼里有另外的含義: 一系列不依賴具體實現的方法的定義。 在 Objective-C 里是通過 protocol 來實現抽象接口的。因為歷史原因,protocol (作為 Java 接口使用)并沒有在 Objective-C 社區里面廣泛使用。一個主要原因是大多數的 Apple 開發的代碼沒有包含它,而幾乎所有的開發者都是遵從 Apple 的模式以及指南的。Apple 幾乎只是在委托模式下使用 protocol。 但是抽象接口的概念很強大,它計算機科學的歷史中就有起源,沒有理由不在 Objective-C 中使用。 我們會解釋 protocol 的強大力量(用作抽象接口),用具體的例子來解釋:把非常糟糕的設計的架構改造為一個良好的可復用的代碼。 這個例子是在實現一個 RSS 訂閱的閱讀器(它可是經常在技術面試中作為一個測試題呢)。 要求很簡單明了:把一個遠程的 RSS 訂閱展示在一個 tableview 中。 一個幼稚的方法是創建一個 `UITableViewController` 的子類,并且把所有的檢索訂閱數據,解析以及展示的邏輯放在一起,或者說是一個 MVC (Massive View Controller)。這可以跑起來,但是它的設計非常糟糕,不過它足夠過一些要求不高的面試了。 最小的步驟是遵從單一功能原則,創建至少兩個組成部分來完成這個任務: - 一個 feed 解析器來解析搜集到的結果 - 一個 feed 閱讀器來顯示結果 這些類的接口可以是這樣的: ~~~ @interface ZOCFeedParser : NSObject @property (nonatomic, weak) id <ZOCFeedParserDelegate> delegate; @property (nonatomic, strong) NSURL *url; - (id)initWithURL:(NSURL *)url; - (BOOL)start; - (void)stop; @end ~~~ ~~~ @interface ZOCTableViewController : UITableViewController - (instancetype)initWithFeedParser:(ZOCFeedParser *)feedParser; @end ~~~ `ZOCFeedParser` 用一個 `NSURL` 來初始化來獲取 RSS 訂閱(在這之下可能會使用 NSXMLParser 和 NSXMLParserDelegate 創建有意義的數據),`ZOCTableViewController` 會用這個 parser 來進行初始化。 我們希望它顯示 parser 接受到的指并且我們用下面的 protocol 實現委托: ~~~ @protocol ZOCFeedParserDelegate <NSObject> @optional - (void)feedParserDidStart:(ZOCFeedParser *)parser; - (void)feedParser:(ZOCFeedParser *)parser didParseFeedInfo:(ZOCFeedInfoDTO *)info; - (void)feedParser:(ZOCFeedParser *)parser didParseFeedItem:(ZOCFeedItemDTO *)item; - (void)feedParserDidFinish:(ZOCFeedParser *)parser; - (void)feedParser:(ZOCFeedParser *)parser didFailWithError:(NSError *)error; @end ~~~ 用合適的 protocol 來來處理 RSS 非常完美。view controller 會遵從它的公開的接口: ~~~ @interface ZOCTableViewController : UITableViewController <ZOCFeedParserDelegate> ~~~ 最后創建的代碼是這樣子的: ~~~ NSURL *feedURL = [NSURL URLWithString:@"http://bbc.co.uk/feed.rss"]; ZOCFeedParser *feedParser = [[ZOCFeedParser alloc] initWithURL:feedURL]; ZOCTableViewController *tableViewController = [[ZOCTableViewController alloc] initWithFeedParser:feedParser]; feedParser.delegate = tableViewController; ~~~ 到目前你可能覺得你的代碼還是不錯的,但是有多少代碼是可以有效復用的呢?view controller 只能處理 `ZOCFeedParser` 類型的對象: 從這點來看我們只是把代碼分離成了兩個組成部分,而沒有做任何其他有價值的事情。 view controller 的職責應該是“從上顯示一些內容”,但是如果我們只允許傳遞`ZOCFeedParser`的話就不是這樣的了。這就表現了需要傳遞給 View controller 一個更泛型的對象的需求。 我們使用 `ZOCFeedParserProtocol` 這個 protocol (在 ZOCFeedParserProtocol.h 文件里面,同時文件里也有 `ZOCFeedParserDelegate` ) ~~~ @protocol ZOCFeedParserProtocol <NSObject> @property (nonatomic, weak) id <ZOCFeedParserDelegate> delegate; @property (nonatomic, strong) NSURL *url; - (BOOL)start; - (void)stop; @end @protocol ZOCFeedParserDelegate <NSObject> @optional - (void)feedParserDidStart:(id<ZOCFeedParserProtocol>)parser; - (void)feedParser:(id<ZOCFeedParserProtocol>)parser didParseFeedInfo:(ZOCFeedInfoDTO *)info; - (void)feedParser:(id<ZOCFeedParserProtocol>)parser didParseFeedItem:(ZOCFeedItemDTO *)item; - (void)feedParserDidFinish:(id<ZOCFeedParserProtocol>)parser; - (void)feedParser:(id<ZOCFeedParserProtocol>)parser didFailWithError:(NSError *)error; @end ~~~ 注意這個代理 protocol 現在處理響應我們新的 protocol 而且 ZOCFeedParser 的接口文件更加精煉了: ~~~ @interface ZOCFeedParser : NSObject <ZOCFeedParserProtocol> - (id)initWithURL:(NSURL *)url; @end ~~~ 因為 `ZOCFeedParser` 實現了 `ZOCFeedParserProtocol`,它需要實現所有需要的方法。從這點來看 view controller 可以接受任何實現這個新的 protocol 的對象,確保所有的對象會響應從 `start` 和 `stop` 的方法,而且它會通過 delegate 的屬性來提供信息。所有的 view controller 只需要知道相關對象并且不需要知道實現的細節。 ~~~ @interface ZOCTableViewController : UITableViewController <ZOCFeedParserDelegate> - (instancetype)initWithFeedParser:(id<ZOCFeedParserProtocol>)feedParser; @end ~~~ 上面的代碼片段的改變看起來不多,但是有了一個巨大的提升。view controller 是面向一個協議而不是具體的實現的。這帶來了以下的優點: - view controller 可以通過 delegate 屬性帶來的信息的任意對象,可以是 RSS 遠程解析器,或者本地解析器,或是一個讀取其他遠程或者本地數據的服務 - `ZOCFeedParser` 和 `ZOCFeedParserDelegate` 可以被其他組成部分復用 - `ZOCViewController` (UI邏輯部分)可以被復用 - 測試更簡單了,因為可以用 mock 對象來達到 protocol 預期的效果 當實現一個 protocol 你總應該堅持 [里氏替換原則](http://en.wikipedia.org/wiki/Liskov_substitution_principle)。這個原則讓你應該取代任意接口(也就是Objective-C里的的"protocol")實現,而不用改變客戶端或者相關實現。 此外這也意味著你的 protocol 不應該關注實現類的細節,更加認真地設計你的 protocol 的抽象表述的時候,需要注意它和底層實現是不相干的,協議是暴露給使用者的抽象概念。 任何可以在未來復用的設計意味著可以提高代碼質量,同時也是程序員的目標。是否這樣設計代碼,就是大師和菜鳥的區別。 最后的代碼可以在這找到。[here](http://github.com/albertodebortoli/ADBFeedReader).
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看