编码灵魂(3)-单一职责原则

引言

我觉得编码是有灵魂的,就像每个人都有信仰一样。那么如何去体现信仰,如何凸显灵魂就需要依赖它所固有的原则。最近学习了设计模式的六大原则,有所感悟,特此做总结和记录。在本文中详细介绍了单一职责原则(SRP)的涵义,同时列出一些简单的例子说明博主自己的看法,希望对大家有所帮助。笔者目前整理的一些blog针对面试都是超高频出现的。大家可以点击链接:http://blog.csdn.net/u012403290

技术点
1、单一职责原则(SPR):通俗来说,就是说一个类或者一个接口专心做好一件事,不去查收别的事。在我们所追求的“高内聚低耦合”在单一职责中也有深刻的体现。“单一职责”标明一个类它对自己负责的事情在类的内部具有非常高的聚合,因为它专心负责一块职责那么它与其他类的耦合也会减少。

一个例子

下面的例子是的确严重违反了单一职责原则,且非常难以阅读和维护。例子的意思是你创建了一个用户服务类,然后你设计的时候,因为发现注册和用户服务有关系,就把这部分设计到了用户(UserService)类中:

package com.brickworkers;

/**
 * 
 * @author Brickworker
 * Date:2017年4月7日下午1:47:51 
 * 关于类UserService.java的描述:单一职责原则示例
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class UserService {

    //用户注册
    public void register(User user){//为什么有人会把注册设计到用户类中,是因为注册肯定会新增一个用户,而理解上就直接放到了用户服务中
        //TODO 相应逻辑
    }
    //用户修改
    public User update(User user){
        //TODO 相应逻辑
    }

    //用户删除
    public boolean delete(User user){
        //TODO 相应逻辑
    }
}

在上面的代码中,UserService主要有三个方法:①用户注册;②用户修改;③用户删除。仔细分析这三个方法发现,其实用户注册并不属于这个类(UserService)的职责,而应该真真实实存在这个类中,比用户注册更合适的应该是用户新增。所以,我们做以下的代码修改:

//修改后的UserService
package com.brickworkers;

/**
 * 
 * @author Brickworker
 * Date:2017年4月7日下午1:47:51 
 * 关于类UserService.java的描述:单一职责原则示例
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class UserService {

    //用户新增
    public User insert(User user){ //这样会提高类的方法的复用
        //TODO 相应逻辑
    }

    //用户修改
    public User update(User user){
        //TODO 相应逻辑
    }

    //用户删除
    public boolean delete(User user){
        //TODO 相应逻辑
    }
}

//新增一个用于管理用户注册的类:
package com.brickworkers;
/**
 * 
 * @author Brickworker
 * Date:2017年4月7日下午1:58:54 
 * 关于类RegisterService.java的描述:单一职责原则分离出来的类
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class RegisterService {
    //用户注册
        public void register(User user){//为什么有人会把注册设计到用户类中,是因为注册肯定会新增一个用户,而理解上就直接放到了用户服务中
            //TODO 相应逻辑
            UserService userService = new UserService();
            userService.insert(user);
        }
}

这样,代码是不是会优雅一点呢?如果项目中有代码写成前面那样,说明模块化划分不够彻底,这是要做一些必要的重构的。再者,我们试想一下,其实在我们日常的开发过程中,只要稍微有点经验的程序员,都会默认的划分出两个类,这个论之为:经验。那么,有什么时候是超出“默认之外”的呢?我们一起来分析下面这段代码。

又一个例子

就我们上面的注册例子,这个时候需求变动了,“要增加一个第三方登录”的功能(假设入参变化很多,无法用简单的user类来存储,需要新增一个extraUser来描述),其实这个就是超出上面所描述的“默认之外”,有些资料上称这种行为为职责扩散,意思就是说原来的功能需要进化,导致它的单一职责分为了更多的职责。那么我们就需要对原来的注册类(RegisterService)进行修改,但是修改又存在好几种办法(这里博主就写2中说明情况):

:在原来的类中进行额外方法添加:

package com.brickworkers;
/**
 * 
 * @author Brickworker
 * Date:2017年4月7日下午1:58:54 
 * 关于类RegisterService.java的描述:单一职责原则分离出来的类
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class RegisterService {
    //用户注册
        public void register(User user){
            //TODO 相应逻辑
            UserService userService = new UserService();
            userService.insert(user);
        }

        //第三方登录
        public void register(ExtraUser euser){
            //TODO 相应逻辑
            EuserService euserService = new EuserService();
            euserService.insert(euser);
        }
}

②:新增一个ExtraUserRegister来支持第三方登录:

package com.brickworkers;

/**
 * 
 * @author Brickworker
 * Date:2017年4月7日下午2:10:19 
 * 关于类ExtraUserRegister.java的描述:单一职责原则第三方登录类
 * Copyright (c) 2017, brcikworker All Rights Reserved.
 */
public class ExtraUserRegister {
    //第三方登录
    public void register(ExtraUser euser){
        //TODO 相应逻辑
        EuserService euserService = new EuserService();
        euserService.insert(euser);
    }
}

我们对这两种方法进行评析。第一种方法,操作简单,但是它违反了单一职责原则,因为第三方登录它所调用的服务和对象本身都发生了巨大的改变,它已经有足够多的理由脱离用户注册类(RegisterService),所以它在后期继续变动中,可能会对原有登录功能造成影响(尝试与原有方法进行修改)。第二种方式,它很好的遵守了单一职责原则,但是在复杂度上就上升了一个台阶,它需要额外的资源去支持这个类,但是后期比较容易维护,同时别人阅读也会更清楚。

或许上面的例子典型没有那么突出,但是大家要理解我意思。其实单一职责核心要看具体情况和你对项目结构的分析理解。如果你觉得两者确确实实有足够理由拆分为两个类分别维护,那么就拆分。如果你觉得,我增加一个方法也能容纳到这个类的职责之中,那么这样做也可以。正如我前两篇博文说到的原则意义,编码规则,过度的遵守会变得“墨守成规”。就像时间复杂度和空间复杂度一样,如果已经达到了某一层面(建立在最大效率的时间和空间),那就要考虑空间换时间或者时间换空间合算不合算,合理不合理了。单一职责也一样,如果一昧的遵守,那么衍生出来的类就太多了。

还有一个问题顺带一提。为什么我没有出现直接修改原来的方法呢?比如说上面的注册类,为什么不直接去修改register()方法,直接在该方法中建立判断是否第三方登录?千万不要这么去做,单一职责要求就是怕你后期因为职责扩散而修改导致了你原来的功能受到影响,所以,稳健起步,如果破话单一职责会让代码逻辑显得更好,也请不要去修改已经存在的功能方法。同时,个人觉得,如果权衡之后发现直接新建一个方法处理更加的便捷的时候,其实在类中方法的层面上来说,也是符合单一职责的(一个方法专门负责传统注册,一个方法专门负责第三方登录)。

好了,以上就是我对单一职责的理解,希望对大家有所帮助。谢谢大家的浏览。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值