ios中生產者模式實例:非激勵廣告架構的優化過程

作者:代培
地址:http://blog.csdn.net/dp948080952/article/details/52972154
轉載請註明出處

前言

這篇博客基於我很久以前在公司項目中做的一個模塊,當時剛做這個模塊的時候完全沒有考慮過設計模式上的東西,一心想着把功能實現了,最後的確是把功能實現了,但是內部邏輯混亂毫無章法,可能當時項目沒有太忙,我的mentor就讓我不斷的優化那個模塊,本來不到一個星期就完成的模塊,加上後面優化的時間竟然是花了整整一個月!後來也做了一個組內的分享,現在也拿來分享給大家吧!

正文

生產者模式

生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。

嚴格意義上來說是沒有生產者模式這一說法的,而是和消費者一起並稱爲生產者消費者模式,生產者消費者模式的核心思想是在生產者和消費者直接插入一個緩衝區,來達到生產者和消費者間的解耦,而我這裏的模塊中沒有這麼一個緩衝區來完成生產者消費者的解耦,所以我姑且稱它爲生產者模式。

需求分析

首先說一下這個非激勵廣告的需求是怎樣的,我們需要在全局的任意一個地方彈出一個廣告,廣告形式爲輪播圖或視頻,而這個廣告內容需要自己下載,展示完成後還需要刪除,一個很簡單的功能,我來列舉一下具體要做哪些:

  • 啓動方法
  • 拉取廣告基礎信息
  • 緩存圖片或視頻
  • 清除緩存
  • 展示入口
  • 廣告展示
  • 廣告點擊跳轉
  • 廣告刷新
  • 保存廣告展示記錄

第一版功能實現

我們看到這一版中可以說是毫無設計,總共只有兩個模塊,分別是負責邏輯的helper類、負責展示的VC。這裏存在哪些問題呢,首先是helper類功能過於複雜,做了些不應該屬於他的事情,比如數據的獲取、處理,而對於VC,他的代理方法設計的很不好,而且對於緩存的刪除工作直接讓VC來做也很不合適(雖然很方便)。

下面分析一下VC這三個代理方法爲什麼不好

  • saveAD(記錄展示過的廣告)
  • refreshTarget(刷新廣告數據)
  • showStoreVC(跳轉到商店頁面)

我們看到這三個方法所做的事情分別是記錄展示過的廣告、刷新廣告數據、跳轉到商店頁面,這些事情嚴格意義來說不應該是VC應該知道的,他所知道的只是view展示出來了,那個button被點擊了諸如此類,這些事情更應該是控制邏輯的helper做的,而且代理這樣寫的化,這個VC的重用性就下降了,他變得十分具體,不夠抽象,只能符合此處一個場景。

第二版優化

我們看到第二版最大的變化就是將數據部分的處理單獨拿了出來:DataController,然而改革的還不夠徹底,比如刪除緩存的任務也應該是dataController做的事情,卻只是從VC轉移到了Helper中,而VC的代理雖然方法名稱改變了,但是實質沒有變,耦合度仍然很高!

而這裏的生產者模式還不明顯,在Helper中start方法中會去調用DataController的下載方法,然後當Helper需要這個下載的東西時就會去問DataController要,生產者沒有一種主動的姿態。

第三版最終版

這一版中有三點要說

  1. 分工清晰
    關於數據的操作無論是數據的下載,處理,記錄,刪除全部交給了DataController,而且接口只有兩個一個是拿數據的接口,一個是刷新數據的接口,其他邏輯都在內部實現;Helper只有兩個接口一個是start使這一整個模塊進入運行狀態,一個是showStoreVC,跳轉到商店頁面;VC只負責展示。
  2. 代理接口合理
    viewDidShow,viewDisappear,confirmButtonClicked,cancelButtonClicked,這幾個接口簡化了View的生命週期,將這些代理出去,已經足夠抽象,Helper根據View不同的狀態,進行不同的操作,如此複用性大大提高,因爲VC也就那幾個生命週期,這些代理已足夠使用。
  3. 生產者模式
    這裏說的生產者模式主要說的是生產者一種主動的態度,DataController的fetch接口帶有一個回調,當調用這個方法時,如果生產者沒有加載好數據,那就等待加載好調用這個回調,將數據返回給調用者,如果還沒開始加載數據,那就立刻加載數據,成功後通過回調給調用者,如果已經有加載好的數據,則立刻通過回調將數據返回給調用者,然後進行下一個數據的加載。
    這樣做有什麼好處呢?避免數據的重複下載,當數據正在加載時,調用這個方法不會開啓另一個下載,而會等下載好並將其傳出去。其次凸現了生成者的主動態度,就是別人需要這個東西了,你生產好了後要主動告訴別人你已經好了,而不是等別人再來問你是不是好了!

生產者消費者模式的思考

在我的這個例子中,確實不能算是標準的生產者消費者模式,但這裏Helper似乎又承擔了生產者和消費者之間的容器,只不過這個容器的容量是1,而且生產者也會承擔緩存儲存的工作,當時已經覺得完美的架構現在看來還是有些不足,緩存的儲存應該專門有一個容器來儲存,將生產者消費者解耦。
所以如果改進我想應該這樣改:

@protocol DataControllerDelegate;
@interface NonRewardAppPromotionDataController : NSObject
@Property (nonatomic, weak) id<DataControllerDelegate> delegate;
- (void)startProducting;
@end
@protocol DataControllerDelegate <NSObject>
- (BOOL)produceAd:(NonRewardAppPromotionViewModel *)viewModel;
@end

生產者只有一個開始生產的接口和一個代理,代理方法根據返回值確定是否繼續生產,在Helper中維護一個容器,當容器量不足時讓生產者開始生產,生產完成後在代理方法中將產品加入容器,如果容器沒滿返回NO生產者繼續生產,容器滿了以後返回YES停止生成,當容器中的產品被使用後,如果低於設定值,讓生產者開始生產。

後記

這個模塊是我開始做iOS後不久寫的東西,所以希望大家見諒當時水平有限。其實現在看來不是什麼複雜的東西,但是在當時看來真的挺複雜,這種設計還是在mentor不停的指導下才不斷完善的,現在回頭看看此時的自己與那時相比應該是有那麼些進步吧!如果你覺得我文中的觀點不正確的化,歡迎留言!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章