类的设计原则——单一职责原则

发布时间 2023-11-23 23:29:21作者: 吧拉吧拉吧

单一职责原则(Single Responsibility Principle, SRP)

  • 单一职责原则,又称单一功能原则,由罗伯特·C.马丁(Robert C. Martin)于《敏捷软件开发:原则、模式和实践》一书中提出。
  • 单一职责原则是指一个类只应该有一个引起变化的原因。换句话说,一个类应该只有一个职责,只有一个修改的原因,如果有多余一个的原因,就需要对类进行拆分。
  • 为什么使每个类只能有一个职责?
    • 因为每一个职责都是变化的一个轴线。当需求变化时,该变化会反映为类的职责的变化。如果一个类承担了多余一个的职责,那么引起它变化的原因就会有多个。而当一个类承担的职责过多,就等于把这些职责耦合在一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合则会导致脆弱的设计,当变化发生的时候,设计会遭到意想不到的破坏。
  • 优点
    • 如果遵循单一职责原则,可以降低类的复杂度,提高类的可读性和可维护性,变更引起的风险降低。
  • 什么情况下需要把两个职责分开?
    • 依赖于应用程序变化的方式。如果应用程序的变化会影响连接函数的签名,那么这个设计就具有僵化性的臭味。另一方面,如果应用程序的变化方式总是导致这两个职责同时变化,那么就不必分离它们。实际上,分离题目就会具有不必要的复杂性的臭味。在此还有一个推论。变化的轴线仅当变化实际发生时才具有真正的意义。如果没有征兆,那么去应用SRP,或者任何其他原则都是不明智的。
  • 举例:经常写项目的时候都需要写用户的登录和注册,有时图省事就会把注册和登录一块写到User,如下面示例代码1。这个时候User类就有两个职责:登录和注册。这违反了单一职责原则。
    • 示例代码1
      public class User {  
          private String username;  
          private String password;  
            
          public User(String username, String password) {  
              this.username = username;  
              this.password = password;  
          }  
            
          public boolean login() {  
              // 登录逻辑...  
              return true;  
          }  
            
          public void register() {  
              // 注册逻辑...  
          }  
      }
      
    • 根据单一职责原则改进代码,就要把登录和注册的功能分离到两个不同的类中,从而使每个类只负责一个职责
      // User类只负责存储用户信息
      public class User {  
          private String username;  
          private String password;  
            
          public User(String username, String password) {  
              this.username = username;  
              this.password = password;  
          }  
          // getter 和 setter 方法...  
      }
      // 登录
      public class LoginService {  
          private User user;  
            
          public LoginService(User user) {  
              this.user = user;  
          }  
            
          public boolean login() {  
              // 登录逻辑...  
              return true;  
          }  
      }
      // 注册
      public class RegistrationService {  
          private User user;  
            
          public RegistrationService(User user) {  
              this.user = user;  
          }  
            
          public void register() {  
              // 注册逻辑...  
          }  
      }
      
  • 总结分析
    • 什么是职责?在SRP中将职责定义为“变化的原因”。
    • SRP的概念看起来很简单,但是很难正确应用,因为我们在实现功能的时候,总是很容易将一部分职责放在一起,在实现过程中才会慢慢发现自己的代码又违背了SRP。