0%

单一职责原则

原文:The Single Responsibility Principle

好的设计的一个最基本原则是:

将改变原因相同的事物放到一起,将改变原因不同的事物分开。

这个原则常被认为是单一职责原则,或者说SRP。简而言之,它是说一个子系统、模块、类、甚至是一个函数,不应该有超过一种以上的改变原因。下面这个例子是一个拥有分别处理业务规则、报告和数据库的方法的类:

1
2
3
4
5
public class Emloyee {
public Money calculatePay() ...
public String reportHours() ...
public void save() ...
}

有些程序员可能会觉得把这三个函数放到同一个类中是非常完美的。毕竟,类被认为是执行公共变量操作的函数的集合。然而,问题在于这三个函数是对完全不同的原因作出的改变。calculatePay函数是作用于薪酬计算时的业务规则。reportHours函数作用于某人期望得到不同格式的报告。save函数作用于数据库管理员变更数据库时。这三种变化原因的结合会让Employee变得不稳定。其中任何原因都会使其发生变化。更重要的是,任何依赖于Employee的类也会跟着受到影响。

好的系统设计意味着我们可以把组件独立部署到系统里。独立部署意味着即使我们修改了某个组件,也没必要去重新部署其他部分。然而,如果Employee被大量地应用到其他组件的类中,每次我们改变Employee都会使其他组件被重新部署,从而抵消了组件设计(或着说SOA,如果你喜欢髦的术语)的好处。下面这种简单的分离就能解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
public class Employee {
public Money calculatePay() ...
}

public class EmployeeReporter {
public String reportHours(Employee e) ...
}

public class EmployeeRepository {
public void save(Employee e) ...
}

每个类都有属于自己的归属。确切地说,所有的报告类都可以放在报告组件中。所有的关系数据库类都可以放在资料库中。所有的业务规则都可以放在业务规则组件中。

精明的读者可能注意到,上边的解决方案仍然是依赖关系。Employee仍然受其它类的依赖。如果Employee被修改了,其他类似乎也不得不重新编译和部署。因此Employee做不到修改后独立部署。然而,其他的类是可以做到修改后独立部署的。对它们当中任何一个的修改都不会迫使其它的重新编译部署。甚至Employee通过谨慎地使用依赖倒置原则(DIP)也能够独立部署,但这是另一本书的主题了。

谨慎应用SRP,把不同变化原因的事物分离开来,是创建具备独立可部署的组件结构的设计关键之一。

小小鼓励,大大心意!