美文网首页
面向对象的原则里氏替换原则

面向对象的原则里氏替换原则

作者: 刘涤生 | 来源:发表于2016-03-17 23:44 被阅读228次

    里氏替换原则

    里氏替换原则的英文全称是Liskov Substitution Principle,缩写是LSP。

    LSP第一种定义是:如果对每一个类型的为S的对象O1,都有类型为T的对象O2,使得以T定义的所有程序P在所有对象O1都替换成O2时,程序P的行为不会发生变化,那么类型S是类型T的子类型。这不太好理解。

    LSP的第二种定义是:所有引用基类的地方必须能透明地使用其子类的对象。通俗的讲就是:只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或者异常,使用者可能根本就不需要知道是父类还是子类,但是,反过来就不行了,有子类出现的地方,父类未必就能适应。因为子类有的东西父类不一定有。

    说了这么多,最终总结就两个字:抽象。为了便于理解这个原则,我们写了一个简单示例来描述,先看UML图:

    里氏替换原则.png

    再来看看具体的代码:

    /**
     * 窗口类
     */
    public class Window  {
    
        public show(View chile) {
            chile.draw();
        }
    }
    
    /**
     * 建立视图抽象,测量视图的宽高为公用代码,绘制实现交给具体的子类
     */
    public abstract class View {
        public abstract void draw();
        public void measure(int width,int height) {
        }
    }
    
    /**
     * Button的具体实现
     */
    public class Button extends View {
    
        @Override
        public void draw() {
            //绘制Button
        }
    }
    
    /**
     * TextView的具体实现
     */
    public class TextView extends View {
    
        @Override
        public void draw() {
            //绘制TextV
        }
    }
    

    上述示例中,Window依赖于View,而View定义了一个视图抽象,measure是各个子类共享的方法,子类通过覆写View的draw方法实现各自的功能。任何继承自View的子类都可以设置给Window的show方法,这就是里氏替换原则。通过里氏替换,就可以自定义各自各样的view,然后传递个Window,Window负责组织view,并且将View显示到屏幕上。

    里氏替换原则的核心是抽象,抽象又依赖于继承这个特性,在OOP当中,继承的优缺点都相当的明显。优点为:

    • 代码重用,减少创建的成本,每个子类拥有父类的方法和属性
    • 子类和父类基本相似,但又与父类有所区别
    • 提高代码的可扩展性,实现父类的方法就可以了,很多开源框架的扩展接口都是通过继承父类完成的。
    • 提高产品或项目的开放性。

    继承的缺点:

    • 继承是侵入性的,只要继承就必须拥有父类的所有属性和方法
    • 可能造成子类代码冗余、灵活性降低,因为子类必须拥有父类的属性和方法
    • 增强了耦合性。当父类的常量、变量和方法被修改时,必须考虑子类的修改,而且在缺乏规范的环境下,这种修好可能带来非常糟糕的结果---大片的代码需要重构。

    结束

    开闭原则中的示例图片缓存系统也很好地反应了里氏替换原则,即MemoryCache、DiskCache、DoubleCache都可以替换成ImageCache的工作,并保证行为的正确性。实际中,开闭原则和里氏替换原则往往是相互关联的,通过里氏替换来达到扩展开放、修改关闭的效果。然而,这两个原则都强调一个OOP的重要特性--抽象。

    参考书籍

    《Android源码设计模式》 何红辉、关爱民著

    相关文章

      网友评论

          本文标题:面向对象的原则里氏替换原则

          本文链接:https://www.haomeiwen.com/subject/zsbclttx.html