《设计模式》杂记之里氏替换原则续

3,覆盖或实现父类方法时输入参数可以被放大
我们可能都知道方法中的输入参数称为前置条件,在里氏替换原则中也有一个契约,就是父类或接口。契约制定了,也就同时制定了前置条件和后置条件,前置条件就是你要让我执行,就必须满足我的条件;后置条件就是我执行完了需要反馈,标准是什么(大家可能对作者的这句话不很理解,其实我和大家刚看的时候都一样不理解啊!)。
那么我们还是通过作者的例子来理解理解吧!呵呵~~(这里我直接用作者的java版代码啦!)
Father类源代码
public class Father {
public Collection doSomething(HashMap map){
System.out.println("父类被执行...");
return map.values();
}
}
子类源代码
public class Son extends Father {
//放大输入参数类型
public Collection doSomething(Map map){
System.out.println("子类被执行...");
return map.values();
}
}
通过子类,我们可以发现子类重载了父类方法。那么在场景类中调用代码如下:
public class Client {
public static void invoker(){
//父类存在的地方,子类就应该能够存在
//Father f = new Father();
Son f =new Son();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void main(String[] args) {
invoker();
}
}
更具里氏替换原则,父类出现的地方子类就可以出现。
public class Client {
public static void invoker(){
//有父类的地方就有子类
//Father f= new Father();
Son f =new Son();
HashMap map = new HashMap();
f.doSomething(map);
}
public static void main(String[] args) {
invoker();
}
}
这两个的运行结果都是一样,通过代码我们了解到父类方法输入参数是HashMap类型,子类的输入参数是Map类型,可以理解成子类的输入参数类型的范围扩大了,子类代替父类传递到调用者中,子类的方法永远都不会被执行。
如果我们想让子类的方法运行,就必须覆写父类方法
那么我们现在反过来想想,如果Father类的输入参数类型宽于子类的输入参数类型。会出现父类存在的地方,子类未必可以存在,因为一旦我们把子类作为参数传入,使用者就很可能进入子类的方法范畴。
所以子类中方法方法的前置条件必须与超类中被覆写的方法的前置条件相同或者更宽松。
4,覆盖或实现父类方法输出结果可以被缩小
父类一个方法的返回值是一个类型T,子类的相同方法(重载或覆写)的返回值为S,在里氏替换原则中要么S和T是同一个类型,要么S是T的子类。
如果是覆写,父类和子类的同名方法的输入参数是相同的,两个方法的范围值S小于等于T。
如果是重载,则要求方法的输入参数类型或数量不相同,在里氏替换原则要求下,就是子类的输入参数宽于或等于父类的输入参数。
引用作者的一段话:我们采用里氏替换原则目的是增强程序的健壮性,版本升级时也可以保持非常好的兼容性,即使增加子类,原有的子类还可以继续运行。

相关文章

迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图...
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,...
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定...
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个...
命令模式(Command)命令模式(Command)[Action/Transactio...
生成器模式(Builder)生成器模式(Builder)意图:将一个对...