设计模式六大原则——里氏替换原则(LSP)

概述

       里氏替换原则(LSP,Liskov Substitution Principle)是关于继承机制的原则,是实现开放封闭原则的具体规范,违反了里氏替换原则必然违反了开放封闭原则。

   引经据典

约瑟夫.斯大林,苏联时期苏联共产党的最高领导人,对于斯大林有没有替身?有几个替身?有一种说法:斯大林有好几个替身,最著名的当属“第一替身”叶夫谢伊.卢比茨基——他“扮演”领袖斯大林长达15年之久,很多高官都被蒙在鼓里。

斯大林作为一国的领导人,肯定要不停的参加各种的聚会,进行各中慰问。。。找几个替身,忙里偷闲或者外出打掩护......

★子类必须完全实现父类的方法

替身代替斯大林去参加各种活动时,他的相貌和一举一动都必须和真的斯大林一模一样,毕竟斯大林代表的是一个国家,如果让别人发现来见自己的是个替身,那不就让人寒心了嘛... 看一下代码:

//斯大林
    public class SiDaLin
    {
        //斯大林讲话行为
        public virtual void SpeakWay()
        {
            Console .WriteLine ("右手举过头顶、伸出两个手指、不断前后摆动,以表示强调或愤慨。")
        }
    }
    //替身
    public class TiShen : SiDaLin
    {
        //替身的讲话行为
        public override void SpeakWay()
        {
            Console .WriteLine ("右手举过头顶、伸出两个手指、不断前后摆动,以表示强调或愤慨。")
        }
    }

不知道大家有没有注意到上面代码中父类中的virtual和子类中的override,为什么要用到它们?

在继承关系中,子类对父类的继承除了字段、属性,还有方法,而使同一方法在子类中表现出不同的行为是通过多态表现的,具体在语言上的操作上表现为父类提供虚函数,而在子类中覆写该虚函数,这是抽象机制的重要基础。

public static void DoSomething(Fatherclass f)
        {
            f.Method();
        }

如果Method被实现为虚函数,并且在子类中被覆写,那么传入DoSomething中的实参既可以是父类,也可以是子类,子类完全可以替代父类在此调用自己的方法,这正是里氏替换原则强调的继承关系,代码如下:

class Fatherclass
    {
        //父类行为
        public virtual void Method()
        {
        }
    }
    class Sonclass :Fatherclass 
    {
        //子类重写父类方法
        public override void Method()
        {
        }         	
    }

(上面这个问题的回答参考《你必须知道的.NET》)

★子类可以有自己的“个性”

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

 就拿斯大林的替身来说,每一个替身都是一个人,都有自己的“个性”,但是他们是斯大林的替身,那么他们平时的表现就必须按照斯大林的表现来,如果他们加入自己的“个性”,那么他们替身的身份就会漏出破绽。

结论

实现开闭原则的关键步骤是抽象化,父类与子类之间的继承关系就是抽象化的体现,因此里氏替换原则是实现开闭原则的具体步骤规范,违反里氏替换原则一定违反开闭原则,反之未必。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏落花落雨不落叶

一个比较有意思的C语言问题

31170
来自专栏专知

【LeetCode 20】关关的刷题日记45 – Valid Parenthese

关关的刷题日记45 – Leetcode 20. Valid Parenthese 题目 Given a string containing just the ...

35570
来自专栏james大数据架构

算法系列

  算法对程序员来说是熟悉的陌生人,编过大量代码后突然被哪个问到算法是什么也有时不知从何说起,简单来说是没有好好总结过仔细分析过。大学里面导师整天苦口婆心的教导...

237100
来自专栏java一日一条

为什么要使用String

这段代码总的来说是OK的。该方法将map中每个Dwarable的key和值,以及和它期望被分解的dwarwleKey一同传得给另一个调用方法。因为功能简单,我就...

7920
来自专栏绿巨人专栏

函数式编程 : 一个程序猿进化的故事

36890
来自专栏数说工作室

提取文本数据,分析师小王初上手!| 【SAS Says·扩展篇】正则表达式

文本分析很有用,数说君自己也玩过,炒鸡有意思,从论坛、网页上爬取网友的舆情数据,然后整理、统计、画图,就可以知道舆论的风暴是什么,可以知道网友最热议的话题、最想...

44360
来自专栏数据结构与算法

P1538 迎春舞会之数字舞蹈

题目背景 HNSDFZ的同学们为了庆祝春节,准备排练一场舞会。 题目描述 在越来越讲究合作的时代,人们注意的更多的不是个人物的舞姿,而是集体的排列。 为了配合每...

30670
来自专栏一个会写诗的程序员的博客

用 Kotlin 的函数式编程 替代 GOF 设计模式用 Kotlin 的函数式编程 替代 GOF 设计模式函数式编程(FP)《Kotlin极简教程》正式上架:

"函数式编程", 又称泛函编程, 是一种"编程范式"(programming paradigm),也就是如何编写程序的方法论。它的基础是 λ 演算(lambda...

17240
来自专栏nummy

抽象工厂模式

当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品。抽象工厂模式提供两个具体工厂角色,分别对应...

11030
来自专栏企鹅号快讯

面向对象的初步理解连载 7

面向对象是一种主流的编程思维,其核心是把现实世界中的对象,对象之间的关系模拟到程序世界中,构造一个软件系统。 Java 是一种典型的面向对象编程语言。这篇文章主...

20890

扫码关注云+社区

领取腾讯云代金券