设计模式六大原则(一)-单一职责

138 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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() {
    }
}

优缺点

  • 类的复杂性降低: 一个类实现什么职责都有清晰明确的定义了, 复杂性自然就降低了
  • 可读性提高: 复杂性降低了,可读性自然就提高了
  • 可维护性提高: 可读性提高了,代码就更容易维护了
  • 变更引起的风险降低: 变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口和类无影响,这对系统的扩展性、维护性都有非常大的帮助