08 SOLID原则之:单一职责

SOLID 原则,实际上是由 5个设计原则组成的,它们分别是:单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则, 为了方便记忆是那个五个设计原则:依次取五个设计原则的首字母 S、O、L、I、D 这 5 个英文字母命名。

单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。这个原则的英文描述是这样的:A class or module should have a single reponsibility。如果我们把它翻译成中文,那就是:一个类或者模块只负责完成一个职责(或者功能)。单一职责原则的核心就是解耦和增强内聚性

怎么判断一个类是否满足单一原则是比较好判断的,但是在设计以及编程的时候,大脑里怎么样区分以及保证编程满足单一原则呢?

为什么一直在强调的单一职责,而实际代码中却屡屡违反呢?

如何判断类的职责是否足够单一?

在设计中很难明确区分是否满足单一,也要结合实际的情况来考虑。

js 复制代码
    private String username;
    private String password;
    private String pubsubTopic;
    private int pubsubPort;
    private Boolean isPc;
    private PubsubClient pubsubClient;
    private TelemetryTool telemetryTool;

分析上面的这个例子,这个例子里包含账号密码,包含常用的打点参数,

  1. 如果整个项目对于安全层级要求较高,要存取在安全秘钥或者秘钥服务器中,那么usernamepassword,就需要自己封装一个类,并且有有网络请求以及加解密和校验逻辑在里面。

  2. 假如说目前对于账号密码的要求较低,并且用户名和密码也不会对业务有很大的影响,单纯是数据查看,并且数据几乎不会变动,那么用户名和密码完全可以存在于Pubsub初始化处理类。

从刚刚这个例子,不同的应用场景、不同阶段的需求背景下,对同一个类的职责是否单一的判定,结论是不一样的。在当下的需求背景下,一个类的设计可能已经满足单一职责原则了,但如果在未来的某个需求背景下,可能就不满足了,需要继续拆分成粒度更细的类。

根据《代码整洁之道》和网上的例子,下面的情况就需要对类进行重构和拆分了:

  • 当类中的代码行数很多时,鼠标滚轮需要滚半天,影响代码的可读性和可维护性,就需要考虑拆分了。
  • 类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;
  • 当给类命名时,发现他既有这个功能,也有那个功能,那么就需要考虑下是不是职责不够清晰,没有遵循单一职责。

编程过程这能够怎么注意实现呢?

其实在我们调用很多模块的方法和监听对象时,想一想,很熟悉的就是继承某个接口,重写某个方法,来单独实现我们需要的功能,我想这就是单一职责的具体体现吧。

1. 方法

js 复制代码
public interface AccountOperate {
    void updateUserName(UserInfo userInfo);

    void updateUserPassword(UserInfo userInfo);
}
js 复制代码
public class AccountOperateImpl implements AccountOperate {
    @Override
    public void updateUserName(UserInfo userInfo) {
        // 修改用户名逻辑
    }

    @Override
    public void updateUserPassword(UserInfo userInfo) {
        // 修改密码逻辑
    }
}

2. 接口

想起来前段时间刚刚加入的业务,有2个弹窗,一个是业务开启的弹窗,另一个是同一隐私的弹窗,两个弹窗前面都是实现的同一个接口

js 复制代码
/** * 弹窗接口 */ 
public interface Dialog {
    // 开启业务
    void agree(); 
    
    // 不同意
    void disAgree(); 
}


//实现-首页
public class ShouPage implements Dialog{

    @Override 
    public void agree() { 
         // 开启业务
    }

    @Override 
    public void disAgree() { 
         // 不同意
    }
}

//实现-设置页面
public class SettingPage implements Dialog{

    @Override 
    public void agree() { 
         // 开启业务
    }

    @Override 
    public void disAgree() { 
         // 不同意
    }
}

刚刚开始业务所有开启入口都实现这个接口,来对用户同意开启业务和拒绝业务,开启隐私和拒绝隐私做处理。后来产品对业务做了调整,但是呢,只对用户开启页面做了修改,隐私页面没有。特别是需要调用接口传参数,连不需要修改的隐私页面也被动做了修改。当时对单一职责不太了解。那现在学习了,应该怎么改呢?

js 复制代码
/** * 弹窗接口 */ 
public interface ProjectDialog {
    // 开启业务
    void agree(int num); 
    
    // 不同意
    void disAgree(); 
}

public interface CookieDialog {
    // 开启业务
    void agree(); 
    
    // 不同意
    void disAgree(); 
}


//实现-首页
public class ProjectPage implements Dialog{

    @Override 
    public void agree(int num) { 
         // 开启业务
    }

    @Override 
    public void disAgree() { 
         // 不同意
    }
}

//实现-设置页面
public class SettingPage implements CookieDialog{

    @Override 
    public void agree() { 
         // 开启业务
    }

    @Override 
    public void disAgree() { 
         // 不同意
    }
}

应该这样设计,不应该贪图省事就混为一谈,导致后面的人修改的时候没有办法进行修改,虽然代码review中,说这一点小修改也没有什么,但是现在想想,确实挺低级的,对自己的应该有一定的要求。

3. 类

因为类是起初实现代码的地方,不能单独为了满足单一职责原则,是不是把类拆得越细就越好呢?答案是否定的。

比如说上面的例子,同意开启隐私和不同意开启隐私,在类中也需要执行单一原则的话,需要拆分成2个类。但是也没有其他的逻辑来实现,那这样显然是多余的。

js 复制代码
/** * 弹窗接口 */ 
public interface ProjectDialog {
    // 开启业务
    void agree(int num); 
    
    // 不同意
    void disAgree(); 
}


//实现-首页
public class ProjectPage implements Dialog{

    @Override 
    public void agree(int num) { 
         // 开启业务
         //写入缓存,记录开关状态
          new ProjectInitManger().initProject()
    }

    @Override 
    public void disAgree() { 
         // 不同意
         //清除缓存,记录开关状态
         new ProjectInitManger().resetProject(f)
    }
}
js 复制代码
public class ProjectInitManger{

    //写入缓存,记录开关状态
    public void initProject()
    
    //清除缓存,记录开关状态
    public void initProject()

}

上面的例子就是对开启应用时状态的记录,没有其他额外的功能,如果强制遵循单一职责的话,那就需要再拆分为2个类,并没有实际的意义。

单一职责原则的优点

  • 类的复杂性降低: 一个类实现什么职责都有明确定义, 复杂性自然就降低
  • 可读性提高: 复杂性降低,可读性自然就提高
  • 可维护性提高: 可读性提高,代码就更容易维护

实际中为什么还会违反单一原则?

一个是真的是对项目不了解,二是对于单一职责不清晰,三是人的惰性,共勉。

相关推荐
用户3721574261354 分钟前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊1 小时前
Java学习第22天 - 云原生与容器化
java
渣哥3 小时前
原来 Java 里线程安全集合有这么多种
java
间彧3 小时前
Spring Boot集成Spring Security完整指南
java
间彧3 小时前
Spring Secutiy基本原理及工作流程
java
数据智能老司机4 小时前
精通 Python 设计模式——创建型设计模式
python·设计模式·架构
Java水解4 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
数据智能老司机5 小时前
精通 Python 设计模式——SOLID 原则
python·设计模式·架构
洛小豆7 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学7 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端