设计原则利剑二--里氏替换原则

前端之家收集整理的这篇文章主要介绍了设计原则利剑二--里氏替换原则前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

英文名称:Liskov Substitution Principle(LSP)

中文名称:里氏替换原则

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

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

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

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

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

作 用:让继承的利大于弊

真 言:时时刻刻记住,在使用父类的时候,随时要想到被子类替换后是否产生错误,所以必须要遵守以上四个原则

说 明:文章系本人学习设计模式后的读后感,属于原创,转载请注明出处,谢谢!本人邮箱:wyxhd2008@yahoo.com.cn

理论实践:

这个设计模式,看了2遍我才看懂意思,特别是什么覆盖后参数的放大,返回结果的缩小,完全被蒙了,其实仔细想想,由于在使用父类的地方可以随时替换成子类,那么自然会出现很多的问题,就自然有了上面条件的限制。按照这个意思来理解,觉得有点像中国式家庭父子关系,父亲的岗位可以替换给子女,但是子女首先必须要会父亲的业务,也允许有一些自己的创新,父亲有了大爱,随时将自己的工作岗位贡献出来了,那么子女当然也要有所付出,也要受到某些限制,如父亲工作的岗位一些默认的潜规则,你仍然得去遵守,尽管你有自己的方法,如果没有遵守父亲的规则去做事情,那么这件事情的成果也必须要小于或等于用父亲的方法做事的成果,可以理解为给父亲面子吧,嘿嘿。这也许就是继承所必须要付出和注意的地方。

用CS游戏中来做个简单的例子,每个士兵都要有枪来杀敌人,枪有很多种类型,手枪,机枪,步枪等,那么所有的枪都从AbstractGun继承过来,那么子类中必须要求全部实现Shoot方法,那么在士兵类中,就不在乎使用的是什么枪,直接用AbstractGun来实现方法调用Shoot,而具体使用什么枪,则可以动态调用,那么此时我们就要考虑到了,如果规定每个士兵只允许时用一种枪支,并且提前将枪支给士兵,那么这个时候在士兵类中就可以直接使用子类了,必须要设计的时候注意替换不会引起程序的错误。具体UML图如下:

上面的设计方式,无论如何替换成子类都不会出现问题,但是此时想想,如果出现了一个玩具枪,给士兵用来练习的,却不能真正在战场上杀敌,但是玩具枪实现不了杀敌人的任务,所以这里不应该将玩具枪放到AbstractGun下面做为子类,即使作为了子类,shoot方法并不能真正杀死敌人,那么士兵在战场的结果就会是死。当然也可以在士兵模块进行判断,判断配发的是否是玩具枪,但是一旦更改了士兵类,那么很多相关的类都会受到影响,如这个士兵类下面很定还会有各种等级的士兵,都必须要做相应的改变。另外,如果是子类,很定会有shoot方法,那么很定会给士兵传递错误的信息。所以将玩具枪不要定义为枪,新的设计方式如下:

按照此次里氏设计原则,就将玩具枪从枪里面彻底分离出来了,我们可以理解为玩具更好,不要理解为枪。要不然会误大事。在这里让我想到自己正在开发的一个项目,也有继承,但是好似没有遵守这个原则,这个类主要用来处理用户数据交互,如刷新,导出数据等操作,其实首页与图形报表根本就不需要上述所说的功能,说到这里这个类连第一个单一职责原则都没有遵守,将数据传输方法应该放入到另外一个类中去实现,这样的操作方式,传递给最上层就是每个模块都有此功能,那么最上层还以为此表有这些操作,虽然这个设计在系统中并不会造成任何影响,但是如果改变一种设计方式,可以让用户体验更好,如果是加载图形主页的时候,我就让最上层的类不要去处理导出事件,快捷键事件,我现在系统的设计如下:

经过重新设计,将HomePageControl,GraPHPageControl独立成2个类,这样每次新增加一个子类的时候没有必要去修改MainForm类了,实现UML图如下:

既然子类要付出那么多,既要全部实现父类的所有功能,还要时刻注意自己的参数以及返回结果,参数可以被放大,而放回值可以被缩小,这样可以避免在某些情况下,父类忽然替换成子类而导致的程序错误,那么子类也有优势,可以自己来实现很多特色功能,如下:我给狙击手配了一把狙击枪。说实在的Rose 比EA难用!!!

而对于其他几条细则,当子类覆盖或者实现父类方法时输入参数可以被放大以及返回参数可以被缩小这个基本用不上,今后系统里所有保持一致就行。避免这样的麻烦事情。

规则不是死的,让软件开发遵守这个规则并不是没有任何意义,而是我们的专家总结出来的经验集合,里氏替换原则,我想不通为什么要去替换?干嘛要去替换呢?不替换不行吗?其实这个规则只是告诉我们在设计的时候如果遵守这个规则,则可以给我们的设计体系带来可扩展性,稳定性等个方面带来好处,如坚持这个原则,那么我的子类必须要实现父类的所有方法,如果子类在继承的时候,要实现自己不需要的方法,那么我们就要考虑是否需要将这个接口或者抽象类进行划分,划分成更小的粒度,遵循了这个规则,其实就自然会遵循了接口分离原则,接口内聚,不要让子类接收没有作用的东西~~

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