• 设计模式—— 一:单一职责原则



    @




    什么是单一设计模式?Why单一设计模式?


    单一职责原则的英文名称是Single Responsibility Principle,简称是SRP。

    在项目中,会用到用户、机构、角色管理这些模块,基本上使用的都是 RBAC模型(Role-Based Access Control,基于角色的访问控制,通过分配和取消角色来完成 用户权限的授予和取消,使动作主体(用户)与资源的行为(权限)分离)。用户有用户管理、修改用户的信息、增加机构(一个人属于多个 机构)、增加角色等信息和行为要维护,假如把这些写到一个接口中, 看看它的类图,如图1-1所示:


    1-1:用户信息维护类图

    在这里插入图片描述

    这个类真的是足够糟糕的!用户的属性和行为都耦合到一块了。为什么不可以呢?因为如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类其它职责的能力,这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

    所以应该把用户的信息抽取成一个BO(Business Object,业务对象),把行为抽取成一个 Biz(Business Logic,业务逻辑),按照这个思路对类图进行修正,如图1-2所示:


    1-2:职责划分后的类图

    在这里插入图片描述


    重新拆封成两个接口,IUserBO负责用户的属性:职责是收集和反馈用户的属性信息;IUserBiz负责用户的行为:职责是完成用户信息的维护和变更。

    看一看分拆成两个接口怎么使用呢?现在是面向接口编程,所以产生了这个UserInfo对象之后,当然既可以把它当IUserBO接口使用,也可以当IUserBiz接口使用。 要获得用户信息,就当是IUserBO的实现类;要是希望维护用户的信息,就把它当作IUserBiz 的实现类。比如:

    IUserInfo userInfo = new UserInfo(); 
    //要赋值了,把它作为一个纯粹的BO 
    IUserBO userBO = (IUserBO)userInfo; 
    userBO.setPassword("abc"); 
    //要执行动作了,把它作为一个业务逻辑类 
    IUserBiz userBiz = (IUserBiz)userInfo; 
    userBiz.deleteUser();
    


    为什么要把一个接口 拆分成两个呢?其实,在实际的使用中,更倾向于使用两个不同的类或接口:一个是 IUserBO,一个是IUserBiz,类图如图1-3所示:

    1-3:项目中经常采用的SRP类图

    在这里插入图片描述


    以上把一个接口拆分成两个接口的动作,就是依赖了单一职责原则,那什么是单一 职责原则呢?

    单一职责原则的定义是:应该有且仅有一个原因引起类的变更。


    More Single! More Single!


    单一职责原则看起来似乎比较简单,实际上软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。在实际的业务当中去把那些职责区分出来不是那么简单。

    比如,生活中常用的电话,通话的时候有4个过程发生:拨号、通话、回 应、挂机,写一个接口,其类图如图1-4所示:


    1-4:电话类图

    在这里插入图片描述

    接口的代码:

    public interface IPhone { 
       //拨通电话 
       public void dial(String phoneNumber); 
       //通话 
       public void chat(Object o); 
       //通话完毕,挂电话
       public void hangup();
    
     }
    

    这个类看起来是没什么问题的。单一职责原则 要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,它就负责一 件事情,上面的接口只负责一件事情吗?是只有一个原因引起变化吗?并不是!

    IPhone这个接口包含了两个职责:一个是协议管理,一个是数传送。

    dial()和hangup()两个方法实现的是协议管理,分别负责拨号接通和挂机;chat()实现 的是数据的传送,把说的话转换成模拟信号或数字信号传递到对方,然后再把对方传递 过来的信号还原成听得懂的语言。实际上,协议接通的变化会引起这个接口或实现类的变化。数据传送的变化同样也会引起这个接口或实现类的变化。那么现在这里就有两个原因都引 起了类的变化。这两个职责会相互影响吗?电话拨号,要能接通就行,不管是电信的还 是网通的协议;电话连接后还关心传递的是什么数据吗?通过这样的分析,发现类图上的IPhone接口包含了两个职责,而且这两个职责的变化不相互影响,那就考虑拆分成两个接口,其类图如图1-5所示:


    1-5: 职责分明的电话类图

    在这里插入图片描述

    这个类图看上去有点复杂了,虽然完全满足了单一职责原则的要求,每个接口职责分明,但是一个手机类要把 ConnectionManager和DataTransfer组合在一块才能使用。组合是一种强耦合关系,你和我都有共同的生命期,这样的强耦合关系还不如使用接口实现的方式,而且还增加了类的复杂性,多了两个类。经过这样的思考后,再修改一下类图,如图1-6所示:


    1-6:简洁清晰、职责分明的电话类图

    在这里插入图片描述

    这里一个类实现了两个接口,把两个职责融合在一个类中。似乎Phone有两个原因引起变化了,但是这是面向接口编程,对外公布的是接口而不是实现类。而且,如果真要实现类的单一职责,这个就必须使用上面的组合模式了,这会引起类间耦合过重、类的数量增加等问题,人为地增加了设计的复杂性。

    单一职责原则的好处:

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

    当然了,追求完美也得从项目的实际功能需求出发。从功能上来说,定义一个IPhone接口也是可行的,实现了电话的功能,而且设计还很简单,仅仅一个接口一个实现类。




    ⇐⇐设计模式——零:设计模式概览      设计模式—— 二:里氏替换原则⇒⇒




    参考:
    【1】:《设计模式之禅》
    【2】:《大话设计模式》
    【3】:面向对象设计原则之单一职责原则

  • 相关阅读:
    Php7安装pdo_pgsql,pgsql扩展
    Laravel 实时监听打印 SQL
    windows 下安装docker依赖boot2docker镜像默认用户和密码
    win7下安装virtual box后启动报错
    phpstorm 不能自动打开上次的历史文件
    BZOJ1001 [BeiJing2006]狼抓兔子 平面图转对偶图,最小割转最短路
    BZOJ1098 [POI2007]办公楼biu
    POJ1410 Intersection
    HDU3336 Count the string
    HDU2594 Simpsons’ Hidden Talents [KMP]
  • 原文地址:https://www.cnblogs.com/three-fighter/p/12347437.html
Copyright © 2020-2023  润新知