定义
一个类或者模块只负责完成一个职责(功能)
不要设计大而全的类,而要设计粒度小、功能单一的类。简单说就是如果一个类包含两个或者两个以上不相干的业务功能,我们就说这个类不符合单一职责原则,应该将这个类拆成多个功能更加单一、粒度更细的类
如何判断类的职责足够单一
举个例子:在一个社交产品中,使用UserInfo表示用户信息,UserInfo类结构如下
type UserInfo struct {
UserID uint64
UserName string
Email string
Telephone string
CreateTime time.Time
LastLoginTime time.Time
AvatarUrl string
ProvinceOfAddress string //省
CityOfAddress string //市
RegionOfAddress string //区
DetailedAddress string //详细地址
// ... 省略其他属性和方法...
}
那UserInfo这个类的职责足够单一吗?
如果用户的地址信息和其他信息一样,只是用来进行展示,那么这个类是符合单一职责的
如果这个社交产品做得好,又添加了电商模块,需要用到用户的地址信息,那么就应该将用户的地址信息拆分出来,拆成一个单独的UserAddress类
如果后续做的非常好,衍生出多个产品,多个产品需要打通用户登录,那么就应该将用户登录的必要信息比如UserName、Email、Telephone拆成一个单独的用户身份认证类
所以,我们可以看出,在不同阶段的需求背景下,对一个类是否满足单一职责的判断是不一样的。在当前阶段的需求背景下,一个类的设计满足单一职责,但是在未来某个阶段的需求背景下,类可能就不满足单一职责了
因此,在实际写代码的时候,我们可以先写一个粗粒度的类满足业务需求,随着业务的发展,如果发现这个类越来越庞大,可以考虑将这个类拆成多个粒度小的类,这就是所谓的持续重构
如何客观判断类的职责是否单一
- 类的代码行数、函数、属性是否比较多,如果比较多,那么就需要拆成多个类
- 该类依赖的其他类或者其他依赖该类的类是否比较多,如果比较多,那么说明类的职责不够单一,需要拆成多个类
- 类的私有方法是不是比较多,如果比较多,是否可以拆到单独的类,供其他类复用
- 类的名字非常难起,很难用一个业务名词概括,只能用一些笼统的词来描述比如Manager、Context等,说明类的职责不单一
- 类中的多个方法只依赖某一部分字段,比如UserInfo中的多个方法只依赖几个地址字段,那么就应该将这些字段、方法拆到
单独的类中 - 当一个类的代码让你读起来比较头大,实现功能的时候不知道该用哪一个函数半天找不着函数,那么就说明这个类比较庞大,
需要进行拆分
类是不是拆的越细越好
不是,类拆的过细,那么内聚性就会变得不好
不管是设计原则还是设计模式,我们都要以可读性、可扩展性、可维护性、可复用性、可测试性等作为最终的衡量标准,而不是死搬硬套这些原则和模式