1. 单一职责原则
基本介绍:一个类只负责一项职责,完成一个单一的功能。
错误的示范
代码语言:javascript复制package principle.singleresponsibility.error;
/**
* 单一职责错误示范
* @author huangfu
*/
public class SingleResponsibilityError {
public void mobile (String vehicle){
System.out.println(vehicle "在公路上跑!");
}
}
代码语言:javascript复制package principle.singleresponsibility.error;
/**
* 单一职责错误的示范的测试
* @author huangfu
*/
public class TestSingleResponsibilityError {
public static void main(String[] args) {
SingleResponsibilityError singleResponsibilityError = new SingleResponsibilityError();
singleResponsibilityError.mobile("汽车");
singleResponsibilityError.mobile("轮船");
singleResponsibilityError.mobile("飞机");
}
}
结果
代码语言:javascript复制汽车在公路上跑!
轮船在公路上跑!
飞机在公路上跑!
上述就违反了单一职责原则,对于不同的交通工具,代码逻辑完全耦合在一起,我们无论修改那一类的交通工具,都会影响其他两种数据
正确的示范
定义接口
package principle.singleresponsibility.correct;
/**
* @author huangfu
*/
public interface TrafficTool {
/**
* 交通工具
* @param trafficToolName
*/
void mobile(String trafficToolName);
}
定义基类,这个主要是对一类的交通工具进行抽象定义,具体的实现可以由子类实现也可直接使用父类的方法
package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 陆地交通工具
* @author huangfu
*/
public abstract class LandTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName "在陆地跑!");
}
}
代码语言:javascript复制package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 海上交通工具
* @author huangfu
*/
public abstract class MaritimeTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName "在海上跑!");
}
}
代码语言:javascript复制package principle.singleresponsibility.correct.base;
import principle.singleresponsibility.correct.TrafficTool;
/**
* 天空交通工具
* @author huangfu
*/
public abstract class SkyTrafficTool implements TrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName "在天空上飞");
}
}
定义具体的实现,可以使用抽象方法也可自己实现逻辑
package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.SkyTrafficTool;
/**
* 飞机交通工具
* @author huangfu
*/
public class AircraftTrafficTool extends SkyTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
代码语言:javascript复制package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.LandTrafficTool;
/**
* 汽车交通工具
* @author huangfu
*/
public class CarTrafficTool extends LandTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
代码语言:javascript复制package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.MaritimeTrafficTool;
/**
* 轮船类交通工具
* @author huangfu
*/
public class SteamshipTrafficTool extends MaritimeTrafficTool {
@Override
public void mobile(String trafficToolName) {
super.mobile(trafficToolName);
}
}
代码语言:javascript复制package principle.singleresponsibility.correct;
import principle.singleresponsibility.correct.base.LandTrafficTool;
/**
* 特殊的交通工具:马
* @author huangfu
*/
public class HorseLandTrafficTool extends LandTrafficTool {
@Override
public void mobile(String trafficToolName) {
System.out.println(trafficToolName "在大草原上跑!");
}
}
测试类
package principle.singleresponsibility.correct;
/**
* @author huangfu
*/
public class TestTrafficTool {
public static void main(String[] args) {
//汽车类
CarTrafficTool carTrafficTool = new CarTrafficTool();
//飞机类
AircraftTrafficTool aircraftTrafficTool = new AircraftTrafficTool();
//轮船类
SteamshipTrafficTool steamshipTrafficTool = new SteamshipTrafficTool();
//特殊的交通工具 马
HorseLandTrafficTool horseLandTrafficTool = new HorseLandTrafficTool();
carTrafficTool.mobile("兰博基尼");
aircraftTrafficTool.mobile("南航");
steamshipTrafficTool.mobile("泰坦尼克号");
horseLandTrafficTool.mobile("汗血宝马");
}
}
结果
代码语言:javascript复制兰博基尼在陆地跑!
南航在天空上飞
泰坦尼克号在海上跑!
汗血宝马在大草原上跑!
上述的完全的描述了单一职责的原则,对某一类交通工具的修改,并不会影响到全局的功能,也可以基于自己的需求来定制自己的交通工具,而不会对全局的功能产生影响!
如何理解单一职责原则呢?
对于单一职责原则我的理解是:一个类只负责完成一个职责或者功能。不要涉及大而全的类,要设计粒度小、功能单一的类。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。
是否有必要对类做一个精准的划分呢?
其实对于不同的业务场景对于单一职责原则的理解都是不一样的,我举个例子是我在极客时间上王争大佬的《设计模式之美》举的一个例子,我觉得甚好,充分的说明了,在不同的业务场景下,类的职责划分也不尽相同!
代码语言:javascript复制我们模拟一个在社交产品中描述用户信息的类
package principle.singleresponsibility.entity;
/**
* 用户信息
* @author huangfu
*/
public class UserInfo {
private String userId;
private String userName;
private String sex;
private Integer age;
private String email;
private String phone;
private long createTime;
private long lastLoginTime;
/**
* 省
*/
private String provinceOfAddress;
/**
* 市
*/
private String cityOfAddress;
/**
* 区
*/
private String regionOfAddress;
/**
* 详细地址
*/
private String detailedAddress;
}
主要争论有两点,第一是觉得这个类符合
单一职责,因为包含的都是跟用户相关的信息,所有的属性和方法都隶属于用户这样一个业务模型,满足单一职责原则!
持不相同的观点:因为这个类里面地址所占比重比较高,所以应该将地址单独抽出来,形成一个userAddress类!这样两个类的职责就更加单一了!
其实两种说法都对,但是他们没有区分业务场景,刚刚也说了,不同的业务模型所对应的设计方案也不尽相同
如果说在社交产品中,地址信息和其他信息完全一致都是做展示用,第一种说法就对,没有必要拆分,他们确实属于一个业务模型,但是如果后来产品做大,用户的地址信息可能会用作用户的收件地址,那么第二种方式就对,因为用户信息和物流信息并不属于一个业务模型!
那么我们还可以在思考,公司越做越好,肯定不止一个社交产品。公司领导希望所有的社交产品的账号和用户信息互通,那么此时我们需要将 userName
,sex
,phone
等信息也拆分出来,以供其他系统使用!
那么我们如何判断我们的类是否足够单一呢?
不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:
- 类中的代码行数、函数或者属性过多;
- 类依赖的其他类过多,或者依赖类的其他类过多;
- 私有方法过多;
- 比较难给类起一个合适的名字;
- 类中大量的方法都是集中操作类中的某几个属性。
总结
事实上,单一职责设计原则正式代码 高内聚低耦合 设计的基石,他通过拆分不同业务,避免不相关的业务耦合在一起,从而提高了代码的高内聚;同时因为类的职责单一,他的耦合性也会相应降低,从而完成开发中一直提倡的 高内聚,低耦合
!