你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 去model化和數據對象

去model化和數據對象

編輯:IOS開發基礎

簡述

去model化這個說法其實有點兒難聽,model化就是使用數據對象,去model化就是不使用數據對象。所以這篇文章主要討論的問題就是:數據傳遞時,是否要采用數據對象?這裡的數據傳遞並不是說類似RPC的場景,而是在單個工程內部,各對象之間、各組件之間、各層之間的數據傳遞。

所謂數據對象,就是把不同類型的數據映射到不同類型的對象上,這個對象僅用於表達數據,數據通過對象的property來體現。瘦Model、貧血模型就屬於這一類。

去Model化,就是不使用特定對象迎合特定數據的映射的方式,來表達數據。比如我們可以使用NSDictionary,或者其他手段例如reformer、virtual record,來避免這種數據映射對象。

關於這個問題的討論涉及以下內容:

  • 如何理解面向對象思想

  • 為什麼不使用數據對象

  • 去Model化都有哪些手段

通過以上三點,我希望能夠幫助大家建立對面向對象的正確理解,讓大家明白如何權衡是否要采用對象化的設計。以及最終當你決定不采用對象化思想而采用非對象化思想時,應該如何進行架構設計。

如何理解面向對象思想

面向對象的思想簡單總結一下就是:將一個或多個復雜功能封裝成為一個聚合體,這個聚合體經過抽象後,僅暴露少部分方法,這些方法向外部獲取實現功能所需要的條件後,就能完成對應功能。傳統的面向過程只針對功能的實現做了封裝,也就是函數。經過這層封裝後,僅暴露參數列表和函數名,用於外部調用者調用並完成功能。

我們可以推導出:函數封裝了實現功能所需要的代碼,因此對象實質上就是再次對函數進行了封裝。將函數集合在一起,形成一個函數集合,面向對象思想的提出者把這個函數集合稱之為對象,把對象的概念從理論映射到實際的工程領域,我們也可以叫它類。

然而我們很快就能發覺,只是單純地把函數集合在一起是不夠的,這些函數集有可能互相之間需要共用參數或共享狀態。因此面向對象的理論設計者讓對象自己也能夠提供屬性(property),來滿足函數集間共用參數和共享狀態的需求。這個函數集現在有了更貼切的說法:領域。因此當這個領域中的個別函數不需要共用參數或共享狀態,僅僅是提供功能時,這些相關函數就可以體現為類方法。當領域裡的函數需要共用參數或共享狀態時,這些函數的體現就是實例方法。

這裡補充一下,領域的概念我們更多會把它理解得比較大,比如多個相關對象形成一個領域。但一個對象自身所包含的所有函數也是一個領域,是大領域裡的一個子領域。

以上就是一個對面向對象思想的樸素理解。在這個理解的基礎上,還衍生出了非常多的概念,不過這並不在本文的討論范圍中。

總之,一個對象事實上是對一個較小領域的一種封裝。對應到本文要討論的問題來看,如果拿一個對象去表達一套數據而非一個領域,這在一定程度上是違背面向對象的設計初衷的。你看著好像是把數據對象化了,就是面向對象編程了,然而事實上並非如此。Martin Fowler早年也在他的《Anemic Domain Model》中提出了一樣的看法:

The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What's worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about.

為什麼不使用數據對象

根據上一小節的內容,我們可以把對象抽象地理解為一個函數集,一個領域。在這一節裡,我們再進一步推導:如果這些函數集裡的所有函數,並不都是處在同一個問題領域內,那麼面向對象的這種實踐是否依舊成立?

答案是成立的,但顯然我們並不建議這麼做。不同領域的函數集如果被封裝在了一起,在實際工程中,這種做法至少會帶來以下問題:

  1. 當需要維護某個問題領域內的函數時,如果修改到某個需要被共用的參數或者需要被共享的對象,那麼其他問題領域也存在被影響的可能。牽一發而動全身,這是我們不希望看到的。

  2. 當需要解決某個問題時,如果引入了某個充滿了各種不同問題領域的函數集,這實質就是引入了對不同問題領域解決方案的依賴。當需要做代碼遷移或復用時,就也要把不相關的解決方案一並引入。拔出蘿卜帶出泥,這也是我們不希望看到的。

當需要維護某個問題領域內的函數時,如果修改到某個需要被共用的參數或者需要被共享的對象,那麼其他問題領域也存在被影響的可能。牽一發而動全身,這是我們不希望看到的。

我們在進行對象化設計時,必須要分割好問題域,才能保證設計出良好的架構。

業界所謂的各種XX建模、XX驅動設計、XXP,大部分其實都是在強調合理分割這一點,他們提供不同的方法論去告訴你應該如何去做分割的事情,以及如何把分割出來的部分再進一步做封裝。然而這些XX概念要成立的話,就都一定需要具備這樣一個前提條件:一個被封裝出來的對象的活動領域,必須要小於等於當前被分割出來的子問題領域。如果不符合這個前提條件的話,一個大的問題領域即使被強行分割成各種小的問題領域,這些小的問題領域還是依舊難以被封裝成為對象,因為對象的跨領域活動勢必就要引入其它領域的問題解決方案,這就使得分割名不副實。

然而,一個被封裝出來的對象的活動領域,必須要小於等於當前被分割出來的子問題領域這個前提在實際業務場景實踐中,是否一定成立呢?如果一定成立的話,那麼這種做法和這些方法論就是沒問題的。如果在某些場景中不成立,對象化設計在這些場景就有問題了。

事實上,這個前提在實際業務場景中,是不一定成立的。在實際業務場景中,一個數據對象被多個業務領域使用是非常常見的。一個數據對象在不同層、不同模塊中被使用也是非常常見的。所以,如果兩個業務對象之間需要傳遞的僅是數據,在這個場景下就不適合傳遞對象化的數據。

當需要解決某個問題時,如果引入了某個充滿了各種不同問題領域的函數集,這實質就是引入了對不同問題領域解決方案的依賴。當需要做代碼遷移或復用時,就也要把不相關的解決方案一並引入。拔出蘿卜帶出泥,這也是我們不希望看到的。

這種場景其實就很好理解了。實際工程中,對象化數據往往不是一個獨立存在的對象,而是依附於某一個領域。例如持久層提供的對象化數據,往往依附於持久層。網絡層提供的對象化數據往往依附於網絡層。當你的業務層某個模塊使用來自這些層的對象化數據時,將來要遷移這個模塊,就必須不得不把持久層或者網絡層也跟著遷移過去。遷移發生的場景之一就是大型工程的組件化拆分,實施組件化時遇到這種問題是一件非常傷腦筋的事情。

小結

所以,在數據傳遞時,我不建議采用對象化設計,尤其是數據傳遞的兩個實體是跨層實體或者跨模塊實體時,對象化設計對架構的傷害非常大。

從實際而非理論的角度上講,數據對象的使用主要存在這些問題:

  1. 數據對象並不符合面向對象的設計初衷

  2. 數據對象有變為支持多領域對象的可能

  3. 數據對象使得領域間依賴性變強

去Model化都有哪些手段

字典流

這種做法是最原始最簡單的做法,我就不多說了。

reformer

reformer是這樣的工作原理:

blob.png

APIManager提供了來自網絡層的數據。Reformer_A,Reformer_B,Reformer_C,分別代表不同的領域。View_A,View_B,View_C,分別就是各領域對不同的數據應用之後產生的結果。在講網絡層的文章中,我設計了reformer的方式來實現非對象化。更詳細的講述和實際的Demo文章裡都有,我在這裡就不多說了。

Virtual Record

Virtual Record事實上把reformer和某個領域相關對象集合在了一起。Virtual Record和reformer的區別在於:reformer更加有利於單數據對應多對象的場景,Virtual Record更加有利於多數據對單對象的場景

blob.png

事實上這幅圖有個地方畫的不太貼切,Virtual Record其實只是View_B的一個protocol,它並不是一個實例,所以才Virtual。關於Virtual Record的詳細解釋和案例,在講持久層的文章裡有。

總結

將數據對象化事實上是一個不符合面向對象思想的做法。

這種說法看起來很反直覺,但事實上如果你對面向對象有深入的理解,就能夠明白其中的原因。這種不符合面向對象思想的做法,也導致了工程實踐上代碼的高耦合和組件難以復用的情況,這都是我們不希望看到的。我在這篇文章裡提供了幾種去Model化的做法,但看起來這應該不是所有的手段,很有可能還有其它方法。未來如果我遇到了其他場景想到了其它方法的話,會對它進行補充。如果各位讀者還有不同的方法或其它的問題,也歡迎在評論區一起交流。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved