在这篇博文中,我想把自己学习过的里氏替换原则一些好知识点分享给大家。首先我想把继承的一下优缺点给大家分享一下,然后再引出里氏替换原则吧!<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
我们都知道在面向对象的语言中,继承是必不可少的,那么它的优点是哪些呢?引用书上一段话吧!
(1)       代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
(2)       提高了代码的重用性;
(3)       子类可以形似父类,但有异于父类;
(4)       提高了代码的可扩展性;
(5)       提高产品或项目的开放性。
既然有了优点就应该有缺点:
(1)       继承是侵入性的。只有继承,就必须拥有父类的所有属性和方法;
(2)       降低代码的灵活性。子类必须拥有父类的属性和方法,让子类受到了许多的约束;
(3)       增强了耦合性。当父类的常量,变量和方法被修改时,必须要考虑子类的修改,更糟糕的结果就是大片的代码需要重构。
C#与C++不同,不支持多重继承(即一个类从多个直接基类派生)。那么这里就引出了里氏替换原则。
里氏替换原则通俗的讲就是:只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或者异常,我们根本不需要知道是父类还是子类。
但是这里我们需要注意的是:有子类出现的地方,父类未必就能适应。
前面我们引出了里氏替换原则的概念,通过这些概念我们可以了解到里氏替换原则为良好的继承定义了一个规范。这里就包含了4层含义:
1,子类必须完全实现父类的方法
《设计模式之禅》这本书上的例子,我个人感觉比较有意思,所以自己就直接把书上的例子分享给大家学习吧!呵呵~~
 书上引用的是CS打枪游戏例子,这里把枪的类图列出:
         <?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
通过这个类图我们可以知道,枪得主要职责是射击,如何设计在各个具体的子类中去定义。在Soldier中定义了一个方法killEnemy,使用枪来杀敌,具体使用什么枪来杀敌人,只有我们在调用时才知道啊!
下面是AbstractGun类的源程序代码:
abstract class AbstractGun
    {
        //射击
        public abstract void shoot();
    }
×××,×××,机枪的实现类源代码:
class Handgun:AbstractGun
    {
        public override void shoot()
        {
            Console.WriteLine("×××射击");
        }
    }
class Rifle:AbstractGun
    {
        public override void shoot()
        {
            Console.WriteLine("×××射击");
        }
    }
class MachineGun:AbstractGun
    {
        public override void shoot()
        {
            Console.WriteLine("机枪扫射");
        }
    }
下面我们来定义一个士兵来使用这些枪吧!代码如下:
class Program
    {
        static void Main(string[] args)
        {
            //产生个士兵
            Soldier soldier = new Soldier();
            //给士兵一支枪
            soldier.setGun(new Handgun());        
            soldier.killEnemy();
            System.Threading.Thread.Sleep(5000);
        }
    }
在这个程序中,在编写程序时Solider士兵类根本不用知道是哪个型号的枪(子类)被传入。
注意:在类中调用其他类时务必要使用父类或接口,如果不能使用父类或接口,则说明类的设计已经违背了LSP原则。
可能有人会说,我们如果使用×××呢?大家可以想象×××是不能用来射击杀死人的,所以说我们就不能写在shoot方法中。下面是ToyGun的源代码:
class ToyGun:AbstractGun
    {
        //×××是不能射击的只能虚构一个了。
        public override void shoot()
        {
            //×××不能杀人,所以这个方法不能实现。
        }
    }
因为我们引入了新的子类,在main方法中源代码如下:
class Program
    {
        static void Main(string[] args)
        {
            //产生一个士兵
            Solder soldier = new Solder();
            soldier.setGun(new ToyGun());
            soldier.killEnemy();
            System.Threading.Thread.Sleep(5000);
        }
    }
在这种情况下,我们发现业务调用类已经出现问题了,正常的业务逻辑不能运行。作者给我们提供了两种解决办法:
1)              在Soldier类中增加判断,如果是×××,就不用来杀人。这个方法可以解决问题,但是在程序中,我们每增加一个类,所有与这个父类有关系的类都必须修改,这样就不可行了。所以这个方案被否定了。
2)              ToyGun脱离继承,建立一个独立的父类,可以与AbstractGun建立关联委托关系。类图如下:
         大家都知道C#的三大特性:继承,封装,多态。继承就是告诉我们拥有父类的方法和属性,然后我们就可以重写父类的方法。那么按照继承原则,我们定义的×××继承AbstractGun是没有问题的。但是我们在具体应用场景中就要考虑这个问题:子类是否能够完整地实现父类的业务。
         注意:如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系,采用依赖,聚合等关系代替继承。
2,子类可以有自己的个性
由于里氏替换原则可以正着用,但是不能反过来用。在子类出现的地方,父类未必就可以胜任。这次我们以×××举例子吧!×××也分为×××和×××,如AK47,AUG×××等等,Rifle子类图如下:
AUG×××源代码如下:
class AUG:Rifle
    {
        public void zoomout()
        {
            Console.WriteLine("通过望远镜观看敌人?");
        }
        public override void shoot()
        {
            Console.WriteLine("AUG射击"); ;
        }
    }
狙击手的源代码如下:
class Sniper
    {
        private AUG aug;
        public void setGun(AUG _aug)
        {
            this.aug = _aug;
        }
        public void killEnemy()
        {
            //首先用望远镜观察
            aug.zoomout();
            //开始射击
            aug.shoot();
        }
    }
那么如何让狙击手使用AUG杀死人呢?
static void Main(string[] args)
        {
            Sniper sniper = new Sniper();
            sniper.setGun(new AUG());
            sniper.killEnemy();
            System.Threading.Thread.Sleep(5000);
        }
在这里,系统直接调用了子类。如果我们这个时候使用父类传递进来呢?代码如下:
static void Main(string[] args)
        {
            Sniper sniper = new Sniper();
            sniper.setGun((AUG)(new Rifle()));
            sniper.killEnemy();
            System.Threading.Thread.Sleep(5000);
        }
 在运行时抛出InvalidCastException异常,从里氏替换原则来看,有子类出现的地方父类未必就可以出现。

转载于:https://blog.51cto.com/wzk89/548618

《设计模式》杂记之里氏替换原则相关推荐

  1. 里氏替换原则——举例说明Java设计模式中的里氏替换原则

    里氏替换原则--举例说明Java设计模式中的里氏替换原则 1. 前言 官方定义: 2. 举例说明 2.1 例子介绍 2.2 反例 2.2.1 类图说明 2.2.2 代码说明 2.2.3 测试 2.2. ...

  2. java设计模式3,里氏替换原则

    目录 一.里氏替换原则定义 二.里氏替换原则的作用 三.违背原则场景 四.里氏替换原则改变代码 1.抽象人物类 2.哪吒子类 3.敖丙子类 五.关注公众号哪吒编程,回复1024,获取Java学习资料, ...

  3. 可能是最好的设计模式入门教程——里氏替换原则

    里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计(OOD)中比较重要.常见的一种,下面来总结里氏替换原则的知识点,包括: 维基百科定义 在面向对象的程序 ...

  4. 设计模式|LSP(里氏替换)原则

    软件质量保障 专注测试圈,自动化测试.测试平台开发.测试新技术.大厂测试岗面经分享, 可以帮忙内推BATJ等大厂!欢迎加VX沟通交流: ISTE1024 在面向对象的语言中,继承是非常优秀的语言机制, ...

  5. java里氏替换原则例子_java设计模式学习笔记——里氏替换原则

    oo中的继承性的思考和说明 1.继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些七月,但是如果子类对这些已经实现的方法任意修改,就会对 ...

  6. 北风设计模式课程---里氏替换原则(Liskov Substitution Principle)

    北风设计模式课程---里氏替换原则(Liskov Substitution Principle) 一.总结 一句话总结: 当衍生类能够完全替代它们的基类时:(Liskov Substitution P ...

  7. 设计模式 里氏替换原则

    设计模式 里氏替换原则 继续里氏替换原则. 上回栗子为正方形不能被长方形继承,这次,具体 子类必须实现父类的方法 类图 对具体代码进行实践 // 定义抽象类枪 public abstract clas ...

  8. 设计模式-里氏替换原则

    设计模式-里氏替换原则 优点 面向对象的语言继承必不可少的,有如下优点 代码共享,减少创建类的工作量 提高代码的重用性 提高代码的可扩展性 提高代码的可扩展性 提高产品代码的开放性 继承侵入性 只要继 ...

  9. 设计模式六大原则之里氏替换原则、依赖倒置原则详解

    设计模式六大原则--里氏替换原则.依赖倒置原则详解 1.里氏代换原则(Liskov Substitution Principle) 概念 顾名思义,该原则用于经常发生替换的地方,在Java中指的是实现 ...

最新文章

  1. keras从入门到放弃(十三)卷积神经网络处理手写数字识别
  2. Docker快速安装与快速入门
  3. 《Booth 空箱》发售一周年回顾
  4. 用C++实现网络编程---抓取网络数据包的实现方法
  5. 【Linux】设置虚拟内存
  6. 136_Power BI 自定义矩阵热力图
  7. 开源数字媒体资产管理系统:Razuna
  8. Visio设计产品流程图
  9. 【软件工程】结构图(SC)——期末复习用
  10. 如何用python爬虫薅羊毛_拼多多现重大BUG被“薅羊毛”,教你如何用Python简单褥羊毛...
  11. HDU 2154:跳舞毯(递推)
  12. riser服务key/value服务介绍-基于leveldb
  13. 一个emoji表情包处理工具类
  14. SQLServer安装程序无法打开注册表项 UNKNOWN\Components\…的问题
  15. JavaWeb技术内幕二:Java IO工作机制
  16. RAID磁盘阵列、mdadm、群晖软RAID
  17. 应用在电磁炉触控面板中的电容式触摸芯片
  18. 维基解密披露CIA对全球上万民众移动端发动攻击
  19. XMU 1071 圣斗士黄金十二宫(七)银河星爆 【计算几何】
  20. Android开发必须会的技能!写给安卓软件工程师的3条建议,Android岗

热门文章

  1. pycharm快敏捷键
  2. 多样化实现Windows Phone 7本地数据访问3——DB4O
  3. SQL SERVER 2005允许自定义聚合函数
  4. java面试④数据库部分
  5. 强迫用户升Win10?旧版Windows放弃对新CPU更新支持
  6. 一个B/S结构自动二次请求需求的实现
  7. ubuntu20.04安装搜狗输入法(社区版+个人版)
  8. 在admin设置第三方帐号登录点击Save保存按钮的时候报错     CSRF token missing or incorrect.
  9. 菜鸟教程-Javascript学习笔记-JS函数之前
  10. ssh遇到port 22:No route to host