重構-Organizing Data

Refactor
(圖片來自: http://sourcemaking.com/)
以下為學習 Organizing Data 的筆記.

Change Bidirectional Association to Unidirectional

兩個 Class 之間有一個雙向的關聯,但其中一個 Class 並無使用到另一個 Class . 將其雙向關聯改成單向關聯.

優點: 降低維護時遭遇的複雜度/耦合度.

Change Reference to Value

如果 Reference Object 很小,很難管理,是不可變性(Immutable)的. 可以把它轉成 Value Object.

以 Java 的 String 來解釋 書中這段解釋不可變性的句子:

you need to replace the existing String object with a new String object rather than changing the content on an exisiting String object.

String msg = "Hi!";
msg.concat("Jack!"); // 直接修改原本的 String .
System.out.print(msg); // 印出"Hi!".

msg = msg.concat("Jack!"); // 用新的 String 取代.
System.out.print(msg); // 印出"Hi!Jack!".

Value Object:

  • 最好是不可變性的.  如果是可變性的,得保證修改某個 Value Object ,其它所有代表同一事物的 Value Object 也得被修改,此時還不如使用 Refernce Object(大家都指向同一個物件位址).
  • 在分散或同步的環境下是很有用的.

範例解釋:

修改前: Currency Class 利用類似 Factory Method Pattern 回傳合適的 Currency ,整個系統只會有一個 Currency 代表 Currency("USD").

因為 Currency 自身維護系統內所有的 Currency 物件,為此將建構子設為 private. -> 造成使用上的不便!? 所以改成 Value Object !? Orz

修改後: 整個系統能有多個 Currency 代表 Currency("USD").

Change Unidirectional Association to Bidirectional

兩個 Class 之間需要使用彼此的功能,但只有單方向的關聯時,加上 Back Pointer ,然後改寫管理兩邊關聯性的方法,使其方法同步修改兩個 Class 彼此間的關聯.

Change Value to Reference

Value and Reference

當你有一個 Class ,它有很多相同的實體,而你想要簡化成單一實體時,將 Value Object 轉成 Refernce Object.

  • Reference Object 就像是客戶/帳號. 每一個 Reference Object 都代表一個存在於真實世界的物件,你必須透過物件身份(Call by Reference)去比對是否相等. ex: 同一家銀行不可能兩個人擁有同一組帳號.
  • Value Object 就像是日期/金錢. 它們完全是根據數量來定義. 你完全不用在意有多少個備份存在於系統. 你不用藉由比對 兩個物件是否一樣(同一個物件) 來確定兩物件是否相同,而只需要覆寫 equal() 和 hashCode(),比對兩物間中你想比對的值(成員變數...). ex: 你可以有一張100元,別人也可以有一張100元,不會有兩個人指向同一張100元.
  • 並不總是很明顯能判斷何時用 Reference / Value .

Duplicate Observed Data

GUI 流程中會產生資料物件的概念,有需要一些跟存取資料相關的方法. 產生一個物件去保存資料,利用 Observer Pattern 來同步 GUI 層/資料層 這兩份資料.

優點: 簡化 UI 的程式碼. 將邏輯和 UI 分開.

Encapsulate Collection

若方法直接回傳 Collection(ex: ArrayList, Set ...),改成回傳不允許修改的 Collection(ex: unmodifiableCollection ...) 並提供 add/remove 的方法.

List friendList = alex.getFriends(); // 回傳整個 List.
friendList = new ArrayList(); // Alex 的朋友清單被別人整個置換而不自知. 在複雜的系統內,這會是一個很難找的的 Bug.

優點: 隱藏資料集合的實作細節. 管理資料集合的操作集中在原本擁有者身上.

Encapsulate Field

將 public 欄位改成 private 欄位,並提供存取方法. Orz -很基本

Organizing Data

Page not Found

Replace Array with Object

幹! 這篇應該要 mail 給我前輩啊!!!

當你有一個陣列,裡頭的元素代表不同的事物時,將 陣列 轉成 物件,陣列內的元素 轉成 物件內的欄位(成員變數).

當你發現你說出 "串列中第三個元素裝的是員工的家庭成員陣列..." 類似的話,相信我! 你應該是在找死! RD 的腦不應該是在裝這些細節啊~!!

優點: 讓 RD 的腦少裝點沒用的東西.

Replace Data Value with Object

Class 內含有一個需要額外行為或其它資料的資料項目時,將其資料項目抽出建立新的物件.

優點: 將責任分散,每個物件只專注在自己該負責的事物上.

Replace Magic Number with Symbolic Constant

程式碼中不要有魔術數字,用常數來替換它.

Replace Record with Data Class

請參考 Replace Array(算是 Record 的一種形式) with Data Object .

Replace Subclass with Fields

子類別間的差異只在於回傳不同資料答案的方法,此時將該方法移至父類別,並刪除衍生的子類別.

  • 有 "行為" 不同於父類別 -> 建立子類別
  • 有 "特性(欄位)" 不同於父類別 -> 不需建立子類別,在父類別利用 Map 來動態儲存變動的特性. 如此就不用維護一堆看起來沒什麼差異的子類別.

Replace Type Code with Class

類別內含有不影響其行為的 Type Code (ex: off = 0, on = 1 ...),產生一個新的 Class 去紀錄這些 Type Code .

優點: 將 Type Code 放置更合適的地方. Type Code 實際對應的值被隱藏起來.

Replace Type Code with State/Strategy

有會影響其行為的 Type Code 而沒有使用子類別,使用 State Pattern / Strategy Pattern 建立對應 Type Code 的子類別.

Replace Type Code with Subclasses

有會影響其行為的 Type Code(Immutable) 而沒有使用子類別,建立對應 Type Code 的子類別.

Self Encapsulate Field

直接存取成員變數 vs 間接存取成員變數

延伸閱讀: http://www.blogjava.net/ivanwan/category/2732.html?Show=All

0 則回應: