你怎麼總是能寫出兩三千行的controller類? 1 程序的modularity 2 大類是怎麼來的?

你一定經常見到一個兩三千行的 controller 類,類之所以發展成如此龐大,有如下原因:

  • 長函數太多
  • 類裏面有特別多的字段和函數
    量變引起質變,可能每個函數都很短小,但數量太多

1 程序的modularity

你思考過爲什麼你不會把all code寫到一個文件?因爲你的潛意識裏明白:

  • 相同的功能模塊無法複用
  • 複雜度遠超出個人理解極限

一個人理解的東西是有限的,在國內互聯網敏捷開發環境下,更沒有人能熟悉所有代碼細節。

解決複雜的最有效方案就是分而治之。所以,各種程序設計語言都有自己的模塊劃分(modularity)方案:

  • 從最初的按文件劃分
  • 到後來使用OO按類劃分

開發者面對的不再是細節,而是模塊,模塊數量顯然遠比細節數量少,理解成本大大降低,開發效率也提高了,再也不用 996, 每天都能和妹紙多聊幾句了。

modularity,本質就是分解問題,其背後原因,就是個人理解能力有限。

說這麼多我都懂,那到底怎麼把大類拆成小類?

2 大類是怎麼來的?

2.1 職責不單一

最容易產生大類的原因

CR一段代碼:


該類持有大類的典型特徵,包含一坨字段:這些字段都缺一不可嗎?

  • userId、name、nickname等應該是一個用戶的基本信息
  • email、phoneNumber 也算是和用戶相關聯
    很多應用都提供使用郵箱或手機號登錄方式,所以,這些信息放在這裏,也能理解
  • authorType,作者類型,表示作者是簽約作者還是普通作者,簽約作者可設置作品的付費信息,但普通作者無此權限
  • authorReviewStatus,作者審覈狀態,作者成爲簽約作者,需要有一個申請審覈的過程,該狀態字段就是審覈狀態
  • editorType,編輯類型,編輯可以是主編,也可以是小編,權限不同

這還不是 User 類的全部。但只看這些內容就能看出問題:

  • 普通用戶既不是作者,也不是編輯
    作者和編輯這些相關字段,對普通用戶無意義
  • 對那些成爲作者的用戶,編輯的信息意義不大
    因爲作者不能成爲編輯。編輯也不會成爲作者,作者信息對成爲編輯的用戶無意義

總有一些信息對一部分人毫無意義,但對另一部分人又必需。出現該問題的癥結在於只有“一個”用戶類。

普通用戶、作者、編輯,三種不同角色,來自不同業務方,關心的是不同內容。僅因爲它們都是同一系統的用戶,就把它們都放到一個用戶類,導致任何業務方的需求變動,都會反覆修改該類,嚴重違反單一職責原則
所以破題的關鍵就是職責拆分。

雖然這是一個類,但它把不同角色關心的東西都放在一起,就愈發得臃腫了。

只需將不同信息拆分即可:

public class User {
  private long userId;
  private String name;
  private String nickname;
  private String email;
  private String phoneNumber;
  ...
}

public class Author {
  private long userId;
  private AuthorType authorType;
  private ReviewStatus authorReviewStatus;
  ...
}

public class Editor {
  private long userId;
  private EditorType editorType;
  ...
}

拆出 Author、Editor 兩個類,將和作者、編輯相關的字段分別移至這兩個類裏。
這倆類分別有個 userId 字段,用於關聯該角色和具體用戶。

2.2 字段未分組

有時覺得有些字段確實都屬於某個類,結果就是,這個類還是很大。

之前拆分後的新 User 類:

public class User {
  private long userId;
  private String name;
  private String nickname;
  private String email;
  private String phoneNumber;
  ...
}

這些字段應該都算用戶信息的一部分。但依然也不算是個小類,因爲該類裏的字段並不屬於同一種類型的信息。
如,userId、name、nickname算是用戶的基本信息,而 email、phoneNumber 則屬於用戶的聯繫方式。

需求角度看,基本信息是那種一旦確定一般就不變的內容,而聯繫方式則會根據實際情況調整,如綁定各種社交賬號。把這些信息都放到一個類裏面,類穩定程度就差點。

據此,可將 User 類的字段分組:

public class User {
  private long userId;
  private String name;
  private String nickname;
  private Contact contact;
  ...
}

public class Contact {
  private String email;
  private String phoneNumber;
  ...
}

引入一個 Contact 類(聯繫方式),把 email 和 phoneNumber 放了進去,後面再有任何關於聯繫方式的調整就都可以放在這個類裏面。
此次調整,把不同信息重新組合,但每個類都比原來要小。

前後兩次拆分到底有何不同?

  • 前面是根據職責,拆分出不同實體
  • 後面是將字段做了分組,用類把不同的信息分別封裝

大類拆解成小類,本質上是個設計工作,依據單一職責設計原則。

若把大類都拆成小類,類的數量就會增多,那人們理解的成本是不是也會增加呢?
這也是很多人不拆分大類的藉口。

各種程序設計語言中,本就有如包、命名空間等機制,將各種類組合在一起。在你不需要展開細節時,面對的是一個類的集合。
再進一步,還有各種程序庫把這些打包出來的東西再進一步打包,讓我們只要面對簡單的接口,而不必關心各種細節。

軟件正這樣層層封裝構建出來的。

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