软件设计重构秘笈27式-26去除上帝类
概念
本文中的”去除上帝类”是指把一个看似功能很强且很难维护的类,按照职责把自己的属性或方法分派到各自的类中或分解成功能明确的类,从而去掉上帝类。
意图
我们经常可以在一些原来的代码中见到一些类明确违反了SRP原则(单一原则), 这些类通常以“Utils”或“Manager”后缀结尾,但有时这些类也没有这些特征,它仅仅是多个类多个方法的组合。 另一个关于上帝类的特征是通常这些类中的方法被用注释分隔为不同的分组。 那么久而久之,这些类被转换为那些没有人愿意进行归并到合适类的方法的聚集地, 对这些类进行重构是将类中的代码按照职责分派到各自的类中,这样就解除了上帝类,也减轻了维护的负担。
案例
public class CustomerService {
public double calculateOrderDiscount(List<Product> products, Customer customer)
{
// do work
return 0;
}
public boolean customerIsValid(Customer customer, Order order)
{
// do work
return false;
}
public List<String> gatherOrderErrors(List<Product> products, Customer customer)
{
// do work
return null;
}
public void register(Customer customer)
{
// do work
}
public void forgotPassword(Customer customer)
{
// do work
}
}
public class Customer {
private double balance;
public boolean isFlagged() {
return balance >= 300;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
public class Order {
}
public class Product {
}
重构
我们看到要重构上面的代码是很简单的,只要将相关的方法按职责分派到对应的类中即可, 带来的好处就是这会降低代码的颗粒度并减少未来维护代码的成本。下面是重构后的代码,它将上面 的代码按照职责分为了两个不同的类。
public class CustomerOrderService {
public double calculateOrderDiscount(List<Product> products, Customer customer)
{
// do work
return 0;
}
public boolean customerIsValid(Customer customer, Order order)
{
// do work
return false;
}
public List<String> gatherOrderErrors(List<Product> products, Customer customer)
{
// do work
return null;
}
}
public class CustomerRegistrationService {
public void register(Customer customer)
{
// do work
}
public void forgotPassword(Customer customer)
{
// do work
}
}
总结
”去除上帝类“是我们经常容易造成的, 第一是因为简便,看到有一个现成的类,大家都会喜欢把代码往里面写,最后导致越写越大, 并且声明功能都有,这样即降低了可读性,也造成了维护的负担。