@Tyhj
        
        2018-07-15T05:33:07.000000Z
        字数 2600
        阅读 1580
    设计模式
原文链接:https://www.zybuluo.com/Tyhj/note/1198744
在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类 
通俗来讲,只要父类能出现的地方子类就能出现。反之,父类则未必能胜任
增强程序的健壮性,即使增加了子类,原有的子类还可以继续运行
对于基类中定义的所有子程序,用在它的任何一个派生类中时的含义都应该是相同的。 
这样继承才不会增加复杂度,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。 
如果我们必须要不断地思考不同派生类的实现在语义上的差异,继承就只会增加复杂度了
“正方形不是长方形”是一个理解里氏代换原则的最经典的例子。在数学领域里,正方形毫无疑问是长方形,它是一个长宽相等的长方形。我们开发的一个与几何图形相关的软件系统中,让正方形继承自长方形是顺利成章的事情。
定义一个长方形类:
public class Rectangle {private int width;private int height;public int getWidth() {return width;}public void setWidth(int width) {this.width = width;}public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}}
定义一个正方形类,继承长方形:
public class Square extends Rectangle {@Overridepublic void setWidth(int width) {super.setWidth(width);super.setHeight(width);}@Overridepublic void setHeight(int height) {super.setHeight(height);super.setWidth(height);}}
类LSPTest是我们的软件系统中的一个组件,它有一个resize方法要用到基类Rectangle,resize方法的功能是模拟长方形宽度逐步增长的效果:
public class LSPTest {/*** 让长方形的宽增加到比长大** @param objRect*/public void resize(Rectangle objRect) {while (objRect.getWidth() <= objRect.getHeight()) {objRect.setWidth(objRect.getWidth() + 1);}}}
我们运行一下这段代码就会发现,假如我们把一个普通长方形作为参数传入resize方法,就会看到长方形宽度逐渐增长的效果,当宽度大于长度,代码就会停止,这种行为的结果符合我们的预期;假如我们再把一个正方形作为参数传入resize方法后,就会看到正方形的宽度和长度都在不断增长,代码会一直运行下去,直至系统产生溢出错误。所以,普通的长方形是适合这段代码的,正方形不适合。 
    我们得出结论:在resize方法中,Rectangle类型的参数是不能被Square类型的参数所代替,如果进行了替换就得不到预期结果。因此,Square类和Rectangle类之间的继承关系违反了里氏代换原则,它们之间的继承关系不成立,正方形不是长方形。
public void resize(Rectangle objRect) {if(objRect instanceof Square){return;}if(objRect instanceof Rectangle){while (objRect.getWidth() <= objRect.getHeight()) {objRect.setWidth(objRect.getWidth() + 1);}}}
效果好像不错,干嘛讲究那么多呢,实现需求是第一位的,这种写法看起来很很直观的,有利于维护。其实这是违背里氏代换原则的,结果就是可维护性和可扩展性会变差。
可以增加一个抽象类Quadrangle,定义四边形的公共方法,Square和Rectangle都从Quadrangle继承这些方法,同时可以添加自己特有的方法(对于resize方法,正方形不继承长方形,就不存在问题了)。
import java.util.HashMap;public class Father {public void func(HashMap m){System.out.println("执行父类...");}}import java.util.Map;public class Son extends Father{public void func(Map m){//方法的形参比父类的更宽松System.out.println("执行子类...");}}import java.util.HashMap;public class Client{public static void main(String[] args) {Father f = new Son();//引用基类的地方能透明地使用其子类的对象。HashMap h = new HashMap();f.func(h);}}
import java.util.Map;public abstract class Father {public abstract Map func();}import java.util.HashMap;public class Son extends Father{@Overridepublic HashMap func(){//方法的返回值比父类的更严格HashMap h = new HashMap();h.put("h", "执行子类...");return h;}}public class Client{public static void main(String[] args) {Father f = new Son();//引用基类的地方能透明地使用其子类的对象。System.out.println(f.func());}}