@原 设计模式之禅——六大原则(里氏替换原则)
里氏替换原则的定义
只要有父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能不需要知道是父类还是子类。但是,反过来就不行,有子类出现的地方,父类未必能适应.
里氏替换原则为良好的继承定义了一个规范,子类必须完全实现父类的方法:
public interface gun{
void shoot();
}
public class A implements S{
void shoot(){
System.out.println("开始射击");
}
}
pulic class B extends A{
void shoot(){ }
}
public class person{
praivate gun mygun;
public void set(gun mygun){
this.mygun = mygun;
}
public void killenemy{
mygun.shoot();
}
}
这里假设在CS场景里,士兵拿着A枪打架,万一你忘记实现B枪(A枪功能的加强)的shoot()方法。那B就无法射击。
注意,在类中调用其他类时务必要使用父类或接口。如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。
继续!如果我们还有一把玩具枪呢
public class ToyGun extends gun{
public void shoot()[
//无实现
}
}
这里,玩具枪不能射击(情景不太合理)。怎么办?
1、用instanceof判断。可是如果再有一种不能射击的枪怎么办。你又要去加代码了。我们要“对修改关闭,对拓展开放”。
2、这里的gun应该是个抽象类
public abstract class gun{
//大量的枪属性。颜色、声音、后坐力...
}
我们可以让玩具枪与gun建立依赖关系。将声音、形状等都委托给gun处理。这样既可以复用代码,又互不影响。
可能我说的不是很清楚,但是这里的总结很清楚:
注意,如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系替代继承。
子类可以有自己的个性。里氏替换是可以正着用,不能反着用,所以子类有自己的个性当然可以。
覆盖或实现父类的方法时输入参数可以被放大
覆盖或者实现父类的方法时输出结果可以被缩小
(采用里氏替换原则时,尽量避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就难以调和了,把子类当作父类使用,子类的”个性“被抹杀了—委屈了点;把子类单独作为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离—缺乏类替换的标准)