【设计模式】里氏代换
里氏代换原则由2008年图灵奖得主、美国第一位计算机科学女博士Barbara Liskov教授和卡内基·梅隆大学Jeannette Wing教授于1994年提出的。 示例为了说明里氏代换是基于一种什么情况而提出的,我们先看这么一个问题。
public class A { public int Add(int a,int b) { return a+b; } } public class Client { public static void main(String[] args){ A a=new A(); System.out.print("20+30="+a.Add(20,30)); } } 运行结果: 20+30=50
在上面的示例中,定义了一个类A,实现了一个加法算法,客户端调用该算法,并打印结果。 现在因为需求的变化,要增加一个功能,由一个新的类B来完成(类B要实现该加法功能,同时还要再添加一个新的功能). 然后采取了这样一种解决方案:因为类A已经实现了一个功能,所以由类B去继承A,然后在去完成第二个功能.
看采取了这种解决方案的算法: public class B extends A{ public int Add(int a,int b) { return a-b; } public void fun(int a) { System.out.print("你输入的数是"+ a); } } public class Client { public static void main(String[] args){ A a=new A();//实例化A B b=new B();//实例化B System.out.println("20+30="+a.Add(20,30));//调用A 的方法 System.out.println("20+30="+b.Add(20,30));//调用B的方法 b.fun(20); } } 运算结果: 20+30=50 20+30=-10 我们会发现当我们使用类B的加法算法的时候我们确得到了一个减法的结果。类A原本正常的功能,因为在B继承后无意识的重写导致原本正常的功能出现了错误。 里氏代换
如果你曾经写过这样的代码,那么你就违背了里氏代换原则. 里氏代换主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中所包含的一些原理。
里氏代换(LSP)可以这样理解:子类可以扩展父类的功能,但不能改变父类的原有功能.或者说任何基类可以出现的地方,子类一定可以出现,反过来是不成立的。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 需要注意的是里氏代换是一种规范,就好像我们国家的官方语言是普通话但是我们的生活中基本上不说普通话同样的道理不使用这个原则我们的代码一样可以跑的好好的但是不可回避的是不遵守这个原则确实会增加出错的几率. 里氏代换包含以下4层含义:
更合理的解决方案
LSP是关于父类和子类的关系。只有当这种关系存在时,里氏代换关系才存在,如果两个具体的类A,B之间的关系违反了LSP的设计,那个根据具体的情况我们可以在采用如下两种方法进行重构。
1.创建一个抽象类C,作为两个具体类的超类,将A,B的共同行为移动到C中来解决
2.从B到A的继承关系改为委派关系。
当我们决定使用继承的时候如果子类不能完整的实现父类的方法,或者父类的某些方法在子类中已经发生了变化,这是我们就要考虑断开父子关系,采用依赖,聚集或组合等关系代替继承。
总结
里氏代换原则是很多设计模式的基础,我们都知道设计模式都是一定程度上遵循开放封闭原则,里氏代换原则和开放封闭原则的联系尤其紧密,违背了里氏代换原则就一定不符合开放封闭原则,因为里氏代换原则是实现开放封闭原则的具体规范。
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |