持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情。
设计模式六大原则(一)----单一职责原则
什么是单一职责原则
对于一些概念,这里描述的不清晰,理解和表达存在偏差,但提供了一些例子供于理解。建议多搜几篇博客对比学习。
单一职责原则的英文名称是Single Responsibility Principle,简称是SRP。
设计模式的目的只有一个:高内聚、低耦合
单一职责原则适用的范围有接口、方法、类。但一般情况下我们只需要保证接口和方法的单一职责,对于类而言符合业务逻辑合理即可。
对于方法而言
比如说有一个描述人活动的方法personActivity,根据传入的枚举做不同的活动。下面的实现将吃饭、学习、睡觉耦合到一起,依赖传参,这样当客户端传参发生错误,那么我们的代码也会报错。显然不合理
class PersonInfo {
}
enum Activity {
EAT, LEARN, SLEEP;
}
interface IPersonActivity {
void personActivity(Activity activity, PersonInfo personInfo);
}
class Person implements IPersonActivity{
@Override
public void personActivity(Activity activity, PersonInfo personInfo) {
if (activity == Activity.EAT){
//doEat
}else if (activity == Activity.LEARN){
//doLearn
}else if (activity == Activity.SLEEP){
//doSleep
}
}
}
可以将方法进行拆分,吃饭、学习、睡觉职责各自单一。
class PersonInfo {
}
interface IPersonActivity {
void eat(PersonInfo personInfo);
void learn(PersonInfo personInfo);
void sleep(PersonInfo personInfo);
}
class Person implements IPersonActivity {
@Override
public void eat(PersonInfo personInfo) {
//doEat
}
@Override
public void learn(PersonInfo personInfo) {
//doLearn
}
@Override
public void sleep(PersonInfo personInfo) {
//doSleep
}
}
对于接口而言
假设一个工厂,存在司机、内勤阿姨。工人的业务我们如何实现呢
如下实现,显然不合理,接口职责不够单一。
interface BusinessWork {
//司机开车
void drive();
//后勤工作
void backOffice();
}
class DriverWorker implements BusinessWork {
@Override
public void drive() {
//司机开车
}
@Override
public void backOffice() {
//司机无需关心后勤,也需要实现,不合理
}
}
class BackOfficeWorker implements BusinessWork {
@Override
public void drive() {
//后勤工作者无需关心开车,也需要实现,不合理
}
@Override
public void backOffice() {
//后勤工作
}
}
拆分,对于公共的工作我们可以统一,但对于各自不同职责得拆分。兵且对于接口可以多实现,细粒度再高,对于实现类来说可以用聚合起来。
每个工人都需要做考勤,所以抽象出一个父接口:BusinessWork。其他工作对其做扩展即可,这样就可以实现解耦。
interface BusinessWork {
void sign();
}
interface DriverBusiness extends BusinessWork {
//司机开车
void drive();
}
interface BackOfficeBusiness extends BusinessWork {
//后勤工作
void backOffice();
}
class DriverWorker implements DriverBusiness {
@Override
public void drive() {
//司机开车
}
@Override
public void sign() {
//打卡签到
}
}
class BackOfficeWorker implements BackOfficeBusiness {
@Override
public void backOffice() {
//后勤工作
}
@Override
public void sign() {
//打卡签到
}
}
对于类而言
从类的层面来讲, 没有办法完全按照单一职责原来来拆分,只要符合业务逻辑,一般都是可行得。
比如对于用户注册、登录、登出而言,我们可以这样实现:
这样设计完全没毛病。
interface IUserBusiness {
void register();
void login();
void logout();
}
class IUserBusinessImpl implements IUserBusiness {
@Override
public void register() {
}
@Override
public void login() {
}
@Override
public void logout() {
}
}
如果非要坚持使用单一原则,可以这样实现:
也没毛病,但是会徒增代码复杂性。
interface iUserBusiness {
}
interface IRegister extends iUserBusiness{
void register();
}
interface ILogin extends iUserBusiness{
void login();
}
interface ILogout extends iUserBusiness{
void logout();
}
class IRegisterImpl implements IRegister {
@Override
public void register() {
}
}
class ILoginImpl implements ILogin {
@Override
public void login() {
}
}class ILogoutImpl implements ILogout {
@Override
public void logout() {
}
}
优缺点
- 类的复杂性降低: 一个类实现什么职责都有清晰明确的定义了, 复杂性自然就降低了
- 可读性提高: 复杂性降低了,可读性自然就提高了
- 可维护性提高: 可读性提高了,代码就更容易维护了
- 变更引起的风险降低: 变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口和类无影响,这对系统的扩展性、维护性都有非常大的帮助