设计模式——六大设计原则之里氏替换原则

来源:互联网 发布:数据库删除一条数据 编辑:程序博客网 时间:2024/06/14 11:14

写在前面:
我的代码大多就是表示一下意思。没有编译过,所以这个UML图也就没画,罪过罪过,嘿嘿嘿 (邪恶脸)

氏替换原则的定义:只要有父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能不需要知道是父类还是子类。但是,反过来就不行,有子类出现的地方,父类未必能适应。


里氏替换原则为良好的继承定义了一个规范,一句简单的定义包含了四层含义。

  • 子类必须完全实现父类的方法:
    这个其实也是编译器强制的,举个例子
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处理。这样既可以复用代码,又互不影响。

可能我说的不是很清楚,但是这里的总结很清楚:
注意,如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖、聚集、组合等关系替代继承。

  • 子类可以有自己的个性。里氏替换是可以正着用,不能反着用,所以子类有自己的个性当然可以。

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

  • 覆盖或者实现父类的方法时输出结果可以被缩小

(采用里氏替换原则时,尽量避免子类的“个性”,一旦子类有“个性”,这个子类和父类之间的关系就难以调和了,把子类当作父类使用,子类的”个性“被抹杀了—委屈了点;把子类单独作为一个业务来使用,则会让代码间的耦合关系变得扑朔迷离—缺乏类替换的标准。)(作者原话)

1 0
原创粉丝点击