定义
单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。这个原则的英文描述是这样的:A class or module should have a single responsibility。如果我们把它翻译成中文,那就是:一个类或者模块只负责完成一个职责(或者功能)。
单一职责原则的定义描述非常简单,也不难理解。一个类只负责完成一个职责或者功能。也就是说,不要设计大而全的类,要设计粒度小、功能单一的类。换个角度来讲就是,一个类包含了两个或者两个以上业务不相干的功能,那我们就说它职责不够单一,应该将它拆分成多个功能更加单一、粒度更细的类。
模拟案例
需求说明
在当前视频网站看视频时,网站针对不同的用户类型,给予不同的服务
访客用户:一般只可以观看480P视频,并时刻提醒注册会员可以观看高清视频。
普通会员:可以观看720P视频,但有广告。
VIP会员:既可以观看1080P视频,又可以关闭或跳过广告。
违背原则方案
/**
* @description:单一职责-模拟场景一般实现
* @version: 1.0
* @Author blackcat
*/
public class VideoUserService {
public void serviceGrade(String userType) {
if ("VIP会员".equals(userType)) {
System.out.println("VIP会员,视频1080P 蓝光");
} else if ("普通会员".equals(userType)) {
System.out.println("普通会员,视频720P 超清");
} else if ("访客用户".equals(userType)) {
System.out.println("访客用户,视频480P 高清");
}
}
//测试
public static void main(String[] args) {
VideoUserService service = new VideoUserService();
service.serviceGrade("VIP会员");
service.serviceGrade("普通会员");
service.serviceGrade("访客用户");
}
}
这一个类里包含了多个不同的行为,拥有多种用户职责。如果继续在类上添加逻辑和拓展功能会显得非常臃肿。如果是几乎不需要迭代的功能,这样的实现也未尝不可。但是面对频繁迭代的业务需求,这样的代码就很难支撑系统迭代,每一次的需求实现会影响其他逻辑,对整个服务有不可控的风险。
单一职责改善代码
定义接口
/**
* @description:用户视频服务接口
* @version: 1.0
* @Author blackcat
*/
public interface IVideoUserService {
/**
* 视频清晰的:480、720、1080
*/
void definition();
/**
* 有无广告
*/
void advertisement();
}
实现类
实现类:访客用户
/**
* @description:访客用户视频服务实现类
* @version: 1.0
* @Author blackcat
*/
public class GuestVideoUserService implements IVideoUserService {
@Override
public void definition() {
System.out.println("访客用户,视频480P 高清");
}
@Override
public void advertisement() {
System.out.println("访客用户,视频有广告");
}
}
实现类:普通会员
/**
* @description:普通会员视频服务实现类
* @version: 1.0
* @Author blackcat
*/
public class OrdinaryVideoUserService implements IVideoUserService {
@Override
public void definition() {
System.out.println("普通会员,视频720P 超清");
}
@Override
public void advertisement() {
System.out.println("普通会员,视频有广告");
}
}
实现类:VIP会员
/**
* @description:VIP会员视频服务实现类
* @version: 1.0
* @create 2022/3/13 14:17
* @Author blackcat
*/
public class VipVideoUserService implements IVideoUserService {
@Override
public void definition() {
System.out.println("VIP会员,视频1080P 蓝光");
}
@Override
public void advertisement() {
System.out.println("VIP会员,视频无广告");
}
}
4.测试
/**
*
* @description:单一职责-模拟场景优化后实现 spring中可用注入的方式
* @version: 1.0
* @Author blackcat
*/
public class VideoUserService {
private Map<String, IVideoUserService> videoMap = new HashMap<>();
{
videoMap.put("访客用户", new GuestVideoUserService());
videoMap.put("普通会员", new OrdinaryVideoUserService());
videoMap.put("VIP会员", new VipVideoUserService());
}
public void serviceGrade(String userType) {
IVideoUserService videoUserService = videoMap.get(userType);
//TODO 空处理
if(ObjectUtil.isNotNull(videoUserService)){
videoUserService.definition();
}
}
//测试
public static void main(String[] args) {
VideoUserService service = new VideoUserService();
service.serviceGrade("VIP会员");
service.serviceGrade("普通会员");
service.serviceGrade("访客用户");
}
}
总结
职责是否单一需要根据业务具体分析进行抽象,不用过度设计,业务、周期多维度统筹
我们在网站首页可以注册, 登录, 登出等操作. 我们通常的做法是:
public interface UserOperate {
void login(UserInfo userInfo);
void register(UserInfo userInfo);
void logout(UserInfo userInfo);
}
public class UserOperateImpl implements UserOperate{
@Override
public void login(UserInfo userInfo) {
// 用户登录
}
@Override
public void register(UserInfo userInfo) {
// 用户注册
}
@Override
public void logout(UserInfo userInfo) {
// 用户登出
}
}
那如果按照单一职责原则拆分, 拆分为下面的形式,这样维护的类就很多
public interface Register {
void register();
}
public interface Login {
void login();
}
public interface Logout {
void logout();
}
public class RegisterImpl implements Register{
@Override
public void register() {
}
}
public class LoginImpl implements Login{
@Override
public void login() {
// 用户登录
}
}
public class LogoutImpl implements Logout{
@Override
public void logout() {
}
}