设计模式学习之设计模式原则(一):单一职责原则和里氏替换原则

前端之家收集整理的这篇文章主要介绍了设计模式学习之设计模式原则(一):单一职责原则和里氏替换原则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

学习设计模式,以《设计模式之禅》为蓝本进行总结与学习,今天先记录设计模式六大原则的两个原则:单一职责原则(SRP)和里氏替换原则(LSP)。


单一职责原则

Single Responsibility Principle(SRP):There should never be more than one reason for a class to change.


看如下一个设计:


思考问题:

1、协议接通的变化会引起这个接口或实现类的变化吗?

2、那数据传送(想想看,电话不仅仅可以通话,还可以上网)的变化会引起这个接口或实现类的变化吗?


很显然会引起变化,这就不符合单一职责原则了,需要做如下改进:



改进后,上述两种情况的变化仅会引起一个接口的变化而不影响其他接口。


单一职责的好处:

1、类的复杂性降低,实现什么职责都有清晰明确的定义;

2、可读性提高,因为复杂性降低,所以可读性提高;

3、可维护性提高,可读性提高,当然更加容易维护;

4、变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。


单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。


下面给出一个方法关联了太多的职责:


改进的类:


改进后,调用更加明确。


对于单一职责原则,我的建议是接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。


里氏替换原则

Liskov Substitution Principle(LSP),definition:

1If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T,the behavior of P is unchanged when o1 is substituted for o2 then S is a sub type of T.

如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

2Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

所有引用基类的地方必须能透明地使用其子类的对象。


第二个定义是最清晰明确的,通俗点讲,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应


LSP为继承定义了良好的原则:

1、子类必须完全实现父类方法

CS游戏中的应用类图:



如果有一把玩具枪(ToyGun),该如何实现?注意:玩具枪不可以射击。




2、子类可以有自己的个性。



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

里氏替换原则要求制定一个契约,就是父类或接口,这种设计方法也叫做DesignbyContract(契约设计)。契约制定了,也就同时制定了前置条件和后置条件,前置条件就是你要让我执行,就必须满足我的条件;后置条件就是我执行完了需要反馈

方法中的输入参数称为前置条件,重载时,要求方法的输入参数类型或数量不相同,在里氏替换原则要求下,就是子类的输入参数宽于或等于父类的输入参数,也就是说你写的这个方法是不会被调用的。


4、覆写或实现父类方法输出结果可以被缩小。

父类的一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,那么里氏替换原则就要求S必须小于等于T


采用里氏替换原则的目的就是增强程序的健壮性,版本升级时也可以保持非常好的兼容性。即使增加子类,原有的子类还可以继续运行。在实际项目中,每个子类对应不同的业务含义,使用父类作为参数,传递不同的子类完成不同的业务逻辑,非常完美!

原文链接:https://www.f2er.com/javaschema/284782.html

猜你在找的设计模式相关文章