更新於 2024/12/18閱讀時間約 5 分鐘

動態改變畫面時的資料處理策略


開發客戶端程式時,有些時候後端傳過來的資料根據情況變化,畫面也有所不同。舉例來說,當使用者登入系統時,後端會根據使用者的權限等級傳送不同的資料,使畫面呈現出不同的功能和選項。另一個例子是,在我們的開發的遊戲中,顯示比賽列表的畫面,也會根據不同的場次型態,顯示不同的卡片樣式。

當回傳資料不一致時,會發生許多 if 判斷式散佈在各個地方,這就是所謂的 Shortgun Surgery 問題。換句話說,當你需要修改一個功能時,你需要在多個地方進行修改,這樣會導致代碼的耦合性增加,並且增加了代碼的維護成本。

舉個例子

在我們的遊戲中,後端會給前端每一場比賽資料,讓前端可以顯示比賽資訊。在下圖中,我們從後端接收了一個 Json 物件,然後把 Json 物件轉換成 Contest 物件,最後一路傳到 View,給 View 決定如何顯示畫面。

在上面的例子中,不同的 Contest 型態,有不同的卡片樣式,當 Contest 的類型不同,後端可能也會根據不同的 Contest 而給前端不同資料,假設我們使用的強型別的語言,那我們到底要如何把不同的 Json 轉成同一個物件呢?

萬能的 Value Object

最簡單解決問題的方式,我們可以在 Contest 放上所有可能的出現的資料,View 則是根據自己的需要選擇相對應的欄位使用。以 Practice Contest View 來說,他只會使用 type 與 spots,但對 Non-Pratice Contest 來說,則是所有欄位都會使用。

優點

  • 容易使用

缺點

  • 使用端依賴了他不需要的東西,違反介面隔離的原則,以 Practice Contest 來說,他並不需要 entryFee 與 maxPrizePool

轉接器模式

另一個例子是,在下面的畫面中,可以發現大部分的畫面樣式都相同,唯一不同的是球員的資訊,不同球類的球員,顯示不同的數值來展示球員的過去表現。以板球球員來說,我們使用 Batting 與 Bowling 表示球員綜合表現,以足球來說,則是使用 Points 表示。

此時大部分的資料都是類似的,只有少部分關於球員表現的資料略微不同,我們可以使用轉接器模式,把後端傳回來的資料,轉換成另一種格式,讓畫面可以用一致的方式操作資料。

以球員表現的例子來説,我們可以把新增一個 Map,用以儲存每種球員數據的 Enum 與其數字,View 在使用時,就可以顯示 Map 中的所有數據即可,而無須關心到底是板球還是足球。

優點

  • 畫面可以使用一致的邏輯處理資料

缺點

  • 當資料差異畫過大時,難以整理成一種共用的格式

策略模式

在我們的遊戲中,我們有許多不同的廣告,有時是單純的一張圖,有時是比賽資訊,而後端則是根據不同情況傳回不同資料。與球員數據問題類似,我們都接收來自後端不大相同的資料,但不同的是,這些資料幾乎沒有共通性,我們難以使用轉接器模式整理出一致的格式。

為了解決這個問題,我們可以使用策略模式,提供一個包含 buildComponent 的方法的介面。當 AdView 從 Controller 取得 Ad 物件時,呼叫 Ad 物件身上的 buildComponent 方法取得顯示用的 Component。 當我們這樣做之後,View 再也無需關心現在到底是哪一種廣告,只需要呼叫 buildComponent 即可取得相對應的廣告畫面,並把它塞進畫面中即可。

在 GeneralAd 與 ContestAd 中,它們會各自實現 buildComponent,提供該類型廣告的 Widget 給 View 顯示。

優點

  • 畫面可以使用一致的邏輯處理資料

缺點

  • Value Object 會認識 View

結論

由於客戶端畫面可能會相當多變,後端可能會給一個 type,不同 type 所包含的資料格式也大不相同,如何處理這個資料與畫面的關係也沒有標準答案,即便問題相似,但是在不同的 Context 之下,也適合不同的解法,只有根據當下情況選擇適當的做法,才能讓後續開發與維護更加順利。

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.