理解:本文中的”去除上帝類”是指把一個看似功能很強且很難維護的類,按照職責把自己的屬性或方法分派到各自的類中或分解成功能明確的類,從而去掉上帝類。
詳解:我們經常可以在一些原來的代碼中見到一些類明確違反了SRP原則(單一原則),這些類通常以“Utils”或“Manager”后綴結尾,但有時這些類也沒有這些特征,它僅僅是多個類多個方法的組合。另一個關於上帝類的特征是通常這些類中的方法被用注釋分隔為不同的分組。那么久而久之,這些類被轉換為那些沒有人願意進行歸並到合適類的方法的聚集地,對這些類進行重構是將類中的代碼按照職責分派到各自的類中,這樣就解除了上帝類,也減輕了維護的負擔。
1 public class CustomerService 2 { 3 public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer) 4 { 5 // do work 6 } 7 8 public bool CustomerIsValid(Customer customer, Order order) 9 { 10 // do work 11 } 12 13 public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer) 14 { 15 // do work 16 } 17 18 public void Register(Customer customer) 19 { 20 // do work 21 } 22 23 public void ForgotPassword(Customer customer) 24 { 25 // do work 26 } 27 }
我們看到要重構上面的代碼是很簡單的,只要將相關的方法按職責分派到對應的類中即可,帶來的好處就是這會降低代碼的顆粒度並減少未來維護代碼的成本。下面是重構后的代碼,它將上面的代碼按照職責分為了兩個不同的類。
1 public class CustomerOrderService 2 { 3 public decimal CalculateOrderDiscount(IEnumerable<Product> products, Customer customer) 4 { 5 // do work 6 } 7 8 public bool CustomerIsValid(Customer customer, Order order) 9 { 10 // do work 11 } 12 13 public IEnumerable<string> GatherOrderErrors(IEnumerable<Product> products, Customer customer) 14 { 15 // do work 16 } 17 } 18 19 public class CustomerRegistrationService 20 { 21 22 public void Register(Customer customer) 23 { 24 // do work 25 } 26 27 public void ForgotPassword(Customer customer) 28 { 29 // do work 30 } 31 }
”去除上帝類“是我們經常容易造成的,第一是因為簡便,看到有一個現成的類,大家都會喜歡把代碼往里面寫,最后導致越寫越大,並且聲明功能都有,這樣即降低了可讀性,也造成了維護的負擔。