设计原则 - 单一职责原则

单一职责原则javascript

定义:单一职责原则的英文名称是Single Responsibility Principle,简称是SRPSRP原则的解释是:There should never be more than one reason for a class to change。即不要存在多于一个致使类变化的缘由,简单来讲:就是一个类只负责一项职责。java

问题由来:假如一个类T负责两个不一样的职责:职责P一、职责P2,若是职责P1需求发生改变而须要修改类T时,有可能会致使本来运行正常的职责P2功能发生故障。也就是说职责P1和P2耦合在一块儿了。函数

解决方案:遵循单一职责原则,将不一样的职责封装到不一样的类或者模块中。分别创建两个类T一、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。.net

 

单一职责原则告诉咱们:设计

一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小并且一个类承担的职责过多,就至关于将这些职责耦合在一块儿,当其中一个职责变化时,可能会影响其余职责的运做,所以要将这些职责进行分离,将不一样的职责封装在不一样的类中,即将不一样的变化缘由封装在不一样的类中,若是多个职责老是同时发生改变则可将它们封装在同一类中。code

 

职责扩散对象

所谓职责扩散,就是由于某种缘由,职责P被分化为粒度更细的职责P1和P2。好比:类T只负责一个职责P,这样设计是符合单一职责原则的。后来因为某种缘由,也许是需求变动了,也许是程序的设计者境界提升了,须要将职责P细分为粒度更细的职责P1,P2,这时若是要使程序遵循单一职责原则,须要将类T也分解为两个类T1和T2,分别负责P一、P2两个职责。可是在程序已经写好的状况下,这样作简直太费时间了。因此,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样作有悖于单一职责原则。(这样作的风险在于职责扩散的不肯定性,由于咱们不会想到这个职责P,在将来可能会扩散为P1,P2,P3,P4……Pn。因此记住,在职责扩散到咱们没法控制的程度以前,马上对代码进行重构。)blog

 

 

单一职责优势接口

一、类的复杂性下降,实现什么职责都有清晰明确的定义ip

二、可读性提升,当复杂性下降以后,那么可读性天然就提升了

三、可维护性提升,由于可读性提升,固然更容易维护了

四、变动引发的风险下降,变动是必不可少的,接口的单一职责作的好的话,一个接口修改只对相应的实现类有影响

五、保证类的单一职责,类会更加的健壮

 

如何定义和区分职责

职责的划分每一个人的理解都不同,很难有标准的答案,并且须要根据项目状况而定,咱们须要作的是让一个类的职责尽量的清楚,保证接口职责单一,类的职责尽量单一,好比:类方法/函数遵循单一职责,只关心输入、输出和职责,不参杂额外的信息。可是实际的开发中有些状况很难真正作到SRP,因此在实际的开发过程当中要学会变通,原本一个类彻底能够实现就没变化必定要拆分为两个类来实现,这样使用聚合或者组合的方式,会增长耦合性和系统的复杂性。不过只要你们都遵循 SRP,那么团队中的每个人都可以开心工做,业务代码易读,健壮性强,可复用性强,你说开不开心。

 

看一个购物车的实例

class Cart {
    // 添加商品
    public func addProduct() { }

    // 移除商品
    public func deleteProduct() {}

    // 获取商品
    public func getProduct() {}

    // 设定订单信息
    public func setOrderInfo(_ info: InfoModel){}

    // 取得付款信息
    public func getPaymentInfo(){}

    // 保存订单
    public func saveOrder(){}
}

能够看到上面Cart类中不只有商品的操做也有订单相关的操做,实际上是不符合单一职责原则的。试想,假如其余地方想使用订单,那么须要建立购物车的实例才可使用,增长了一些没必要要的操做,若是咱们把订单做为一个单独的类来处理,那么购物车和订单之间相互没有关系,使用起来很是方便。

class Cart {
    // 添加商品
    public func addProduct() { }

    // 移除商品
    public func deleteProduct() {}

    // 获取商品
    public func getProduct() {}
}

class Order {
    // 设定订单信息
    public func setOrderInfo(_ info: InfoModel){}

    // 取得付款信息
    public func getPaymentInfo(){}

    // 保存订单
    public func saveOrder(){}
}

能够看到如今使用起来就很是容易了,无论哪里须要订单内容,实例化Order对象进行相关操做便可,并且对订单进行修改也不会影响购物车,这彻底体现了SRP。总之,本身作本身的事情,不要作跟本身不相关的事情就好。

 

参考

单一职责原则