小酌重構系列[12]——去除上帝類
關于上帝類
神說:“要有光”,就有了光。——《圣經(jīng)》。上帝要是會寫程序,他寫的類一定是“上帝類”。程序員不是上帝,不要妄想成為上帝,但程序員可以寫出“上帝類”。上帝是唯一的,上帝的光芒照耀人間,上帝是很愛面子的,他知道程序員寫了“上帝類”,搶了他的風頭,于是他降下神罰要懲戒程序員。——既然你寫了“上帝類”,那么就將你流放到艱難地修改和痛苦的維護的煉獄中,在地獄之火中永久地熬煉。
你看,上帝也是有脾氣的,你做了什么他都知道,你不能搶他的風頭,否則你就要付出代價,受到相應的懲罰。為息帝怒,咱們還是老老實實地編寫一些“小類”吧。
有些開發(fā)者為了貪圖簡便,看到一個現(xiàn)成的類,也不管這個類是做什么的,需要追加功能時,就向這個類里面添加功能代碼。久而久之,使得一些類變成了“上帝類”。什么是“上帝類”?上帝類也叫萬能類,意指做了太多“事情”的類。在開發(fā)基于WebForms的應用程序時,Page頁面的后置代碼中包含了訪問數(shù)據(jù)庫、處理業(yè)務邏輯、綁定頁面數(shù)據(jù)、頁面事件處理等這些事情,這就是上帝類的一個舉證(可能很多人都這么干過)。
上帝類的優(yōu)缺點
優(yōu)點
“存在即合理”——上帝類比較適用于一些較小的、穩(wěn)定的應用開發(fā)場景,即那些業(yè)務邏輯不復雜、也不需要太多維護的應用程序。
比如:一些小工具的開發(fā),不需要過多地考慮類的粒度和職責劃分,樓主博客中用的Windows Live Writer代碼高亮插件就是這么做的。
缺點
上帝類的缺點是顯而易見的,上帝類的顆粒度較大,它缺乏可讀性、可擴展性和可維護性。
上帝類違反了“SRP原則”,上帝類擔任的職責太多了,該做的和不該做的它都做了。
同時也違反了“OCP原則”,上帝類功能之間的耦合性太高了,因此不具備可擴展性,當需求變化時,可能會涉及到大量代碼的修改。
“SRP原則”和“OCP原則”的我就不再贅述了,想了解這兩個原則,請參考該系列的另外兩篇文章:分離職責和提取接口。
示例
重構前
下面這個CustomerService類,定義了5個方法:
- CalculateOrderDiscount()方法:結合客戶信息,計算訂單的折扣
- CustomerIsValid()方法:結合訂單信息,判斷客戶是否有效
- GatherOrderErrors()方法:結合訂單的商品信息和客戶信息,收集訂單錯誤信息
- Register()方法:注冊客戶信息
- ForgotPassword()方法:處理客戶忘記密碼
public class CustomerService
{
public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
{
// do work
}
public bool CustomerIsValid(Customer customer, Order order)
{
// do work
}
public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
{
// do work
}
public void Register(Customer customer)
{
// do work
}
public void ForgotPassword(Customer customer)
{
// do work
}
}
在業(yè)務上,這些方法多少和Customer是有一些關聯(lián)的。但這不意味著,只要是和Customer相關的方法都要放到CustomerService中。
這個類還可以在職責上做一些劃分,粒度可以控制的在細一些。
重構后
重構后,我們按職責將CustomerService拆分為了CustomerOrderService和CustomerRegistrationService。
public class CustomerOrderService
{
public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer)
{
// do work
}
public bool CustomerIsValid(Customer customer, Order order)
{
// do work
}
public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer)
{
// do work
}
}
public class CustomerRegistrationService
{
public void Register(Customer customer)
{
// do work
}
public void ForgotPassword(Customer customer)
{
// do work
}
}
拆分后,我們可以看到:
- 這兩個類的語義和它們的命名以及定義在其中的方法都是契合的。
- 類的粒度變小了,代碼的可讀性增強了,并且有利于將來的擴展、維護、修改。
在開發(fā)過程中,我們應該保持一個良好的習慣,為類中追加功能時,盡量確認好類的職責,并控制好類的粒度,這有益于代碼的可讀性、擴展性、維護和修改,這樣就不會被上帝發(fā)現(xiàn)了。
本文鏈接: 文章作者:keepfool 文章出處:http://www.rzrgm.cn/keepfool/ 如果您覺得閱讀本文對您有幫助,請點一右下角的“推薦”按鈕,您的“推薦”將是我最大的寫作動力!歡迎看官們轉(zhuǎn)載,轉(zhuǎn)載之后請給出作者和原文連接。

有些開發(fā)者為了貪圖簡便,看到一個現(xiàn)成的類,也不管這個類是做什么的,需要追加功能時,就向這個類里面添加功能代碼。久而久之,使得一些類變成了“上帝類”。什么是“上帝類”?上帝類也叫萬能類,意指做了太多“事情”的類。在開發(fā)過程中,我們應該保持一個良好的習慣,在類中追加功能時,一定要事先確認類的職責,并控制好類的粒度,這有益于代碼的可讀性、擴展性、維護和修改。
浙公網(wǎng)安備 33010602011771號