一、定义
单一职责原则(Single Responsibility Principle),简称SRP。
There should never be more than one reason for a class to change.
应该有且仅有一个原因引起类的变更。
单一职责的意义:
1、降低类的复杂性,实现什么样的职责都有清晰的定义
2、提高可读性
3、提高可维护性
4、降低变更引起的风险,对系统扩展性和维护性很有帮助
个人理解是:接口和方法一定要做到单一职责,不能在一个接口中定义多种业务逻辑;也尽量避免在一个方法里完成多项任务。对于类来说,如果严格按照单一职责原则来的话会导致类过多,代码过于分散,依赖关系变得复杂,所以在类中需要结合业务来对其职责进行折中划分。
二、示例
在平时开发过程中,增删改查是遇到最常见的业务逻辑,用大类来划分,增删改属于写操作,查询属于读操作。所以在对外提供服务的时候一般是将读和写分开的,因为对于读来说,也许需求变化会更多一些,而写操作则是变化少一些,如果都放在一个接口里定义,那么,在增加读操作的时候,势必会影响到写操作,反之亦然。如下示例:
先定一个JavaBean
package com.dp.srp;
public class UserVO {
private String name;
private String sex;
private int height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
定义接口:
package com.dp.srp;
public interface IUserService {
public UserVO query(String name );
public void insert(UserVO user);
public void update(UserVO user);
public void delete(UserVO user);
}
定义读操作实现类:
package com.dp.srp.impl;
import com.dp.srp.IUserService;
import com.dp.srp.UserVO;
public class UserQueryServiceImpl implements IUserService{
@Override
public UserVO query(String name) {
System.out.println("我是查询");
//过程省略
UserVO user = new UserVO();
return user;
}
@Override
public void insert(UserVO user) {
//do nothing
}
@Override
public void update(UserVO user) {
//do nothing
}
@Override
public void delete(UserVO user) {
//do nothing
}
}
定义写操作实现类:
package com.dp.srp.impl;
import com.dp.srp.IUserService;
import com.dp.srp.UserVO;
public class UserMaintainServiceImpl implements IUserService{
@Override
public UserVO query(String name) {
//do nothing
return null;
}
@Override
public void insert(UserVO user) {
System.out.println("我是新增");
}
@Override
public void update(UserVO user) {
System.out.println("我是修改");
}
@Override
public void delete(UserVO user) {
System.out.println("我是删除");
}
}
我们可以看到,在读和写的实现类里都有跟自己业务不相关的操作定义,如果我们现在想增加一个方法,根据多个名称查询,那现在读写操作需要去实现新增的方法。
public UserVO query(String [] names );
这就违背了单一职责原则。
三、修改
现在定义两个接口,读和写。
写操作接口定义:
package com.dp.srp;
public interface IUserMaintainService {
public void insert(UserVO user);
public void update(UserVO user);
public void delete(UserVO user);
}
package com.dp.srp;
public interface IUserQueryService {
public UserVO query(String name );
public UserVO[] query(String [] names );
}
读和写操作实现类定义:
写操作实现定义:
package com.dp.srp.up.impl;
import com.dp.srp.IUserMaintainService;
import com.dp.srp.UserVO;
public class UserMaintainServiceImpl implements IUserMaintainService{
@Override
public void insert(UserVO user) {
System.out.println("我是新增");
}
@Override
public void update(UserVO user) {
System.out.println("我是修改");
}
@Override
public void delete(UserVO user) {
System.out.println("我是删除");
}
}
读操作实现定义:
package com.dp.srp.up.impl;
import com.dp.srp.IUserQueryService;
import com.dp.srp.UserVO;
public class UserQueryServiceImpl implements IUserQueryService{
@Override
public UserVO query(String name) {
System.out.println("我是查询");
//过程省略
UserVO user = new UserVO();
return user;
}
@Override
public UserVO[] query(String[] names) {
// TODO Auto-generated method stub
return null;
}
}
这样再我们修改读写的时候就不要相互干扰。
当然可能有的网友会问,为什么不为每个操作定义一个接口,这样不是依赖更小,职责更单一么?
这样的认为也是对的,单一职责原则没有说一定要严格遵循,划分尺度也是要按照业务要求来进行。如果我们的服务是对外的,比如微信的各种号,那么我认为是需要划分到最细的粒度,尽量减小改变带来的影响;如果服务是对内,没有跨模块或者系统,那么按照读写来分离我认为是比较合理的。