您的位置:首页 > 其它

设计原则解读——单一职责原则、里氏替换原则

2014-04-09 00:00 295 查看
摘要: 在正式学习设计模式前,对6大设计原则中的单一职责原则和里氏替换原则做出简单介绍。

单一替换原则

定义:There should never be more than one reasion for a change.

应该有且仅有一个原因引起类的变更(类的职责应该尽可能的单一)。

如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。

例如:

对于一个用户管理类,应该把用户信息抽取成BO(接口),把行为抽取成Biz(接口),最后继承这两个接口。

反思在之前很多的编码当中,单一职责考虑的不够,需求或其他模块的变化最终导致代码大规模的修改。

面向接口编程与单一职责:

一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责。

单一职责应该考虑面向接口编程,每个接口职责分明,然后把多个职责融合在一个类中。而不是采用组合模式,因为组合本身是一种强耦合关系。

单一职责能给我们在编程中带来如下好处:

降低类的复杂度,提高可读性,提高可读性;

变更引起的风险降低,对系统扩展性,维护性都有很大帮助

最后:单一职责不仅适用于接口和类,同时适用于方法,一个方法应该尽可能做一件事情,避免一个方法的颗粒度粗。

在实际项目中可能经常违背单一职责,接口一定要做到单一职责,类的设计尽量做到一个原因引起变化。

里氏替换原则(LSP原则)

通俗理解:只要父类出现的地方子类就可以出现,替换不会产生任何错误和异常。

“继承必须确保超类所拥有的性质在子类中仍然成立。”也就是说,当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系。

里氏替换原则隐含的四层含义:

子类必须完全实现父类的方法

子类可以有自己的“个性”

覆盖或实现父类的方法时输入参数可以被放大

覆盖或实现父类的方法时输出结果可能被缩小

对以上四层的说明:

1. 是否继承?

实际设计中如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,应该断开继承关系,采用依赖,聚集,组合等关系代替继承(实际编码中继承应该谨慎被使用,继承是侵入式的,增加了子类的约束,增强了类之间的耦合性)。在类中调用其他类时务必要使用父类或接口,如果不能使用父类或借口,则说明类的设计已经违背了LSP原则。

2.里氏替换原则逆用?

在子类出现的地方,父类未必就能够胜任。也就是常说的向下转型(downcast)是不安全的(里氏替换原则反过来未必成立)。
3.前置条件、后置条件、不变式
前置条件:每个方法调用之前,该方法应该校验传入参数的正确性,只有正确才能执行该方法,否则认为调用方违反契约,应不予执行。

后置条件:一旦通过前置条件的校验,方法必须执行,并且必须确保执行结果符合契约。

不变式:对象本身有一套对自身状态进行校验的检查条件,以确保该对象的本质不发生改变。

4.输入、输出与LBS

了满足LSP,当存在继承关系时,子类中方法的前置条件必须与超类中被覆盖的方法的前置条件相同或者更宽松(避免业务逻辑的混乱);

而子类中方法的后置条件必须与超类中被覆盖的方法的后置条件相同或者更为严格。

继承并且覆盖超类方法的时候,子类中的方法的可见性必须等于或者大于超类中的方法的可见性,子类中的方法所抛出的受检异常只能是超类中对应方法所抛出的受检异常的子类。

5.里氏替换原则的目的

采用里氏替换原则的目的就是为了增强程序的健壮性,可扩展性。

6.子类的“个性”。

当一个子类很个性时,这个子类就和父类的关系很难调和,把子类当做父类使用会使子类失掉“个性”。

但是若独立作为一个业务使用,又会使代码间耦合关系不清晰。

参考资料:

《设计模式之禅》 机械工业出版社 秦小波著

百度百科——单一职责原则、里氏替换原则

来自互联网其它资料
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: