精华内容
下载资源
问答
  • 里氏替换原则Demo

    2015-11-28 16:31:20
    http://blog.csdn.net/xingjiarong/article/details/50081857
  • 本文实例讲述了PHP面向对象之里氏替换原则。分享给大家供大家参考,具体如下: 里氏替换原则(Liskov Substitution Principle) 里氏替换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生...
  • 里氏替换原则的定义 里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和...

    里氏替换原则的定义

    里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和层次》(Data Abstraction and Hierarchy)里提出来的,她提出:继承必须确保超类所拥有的性质在子类中仍然成立(Inheritance should ensure that any property proved about supertype objects also holds for subtype objects)。

    里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。

     

    里氏替换原则的作用

    里氏替换原则的主要作用如下。

    1. 里氏替换原则是实现开闭原则的重要方式之一。
    2. 它克服了继承中重写父类造成的可复用性变差的缺点。
    3. 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。

     

    里氏替换原则的实现方法

    里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

    如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。

    如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。

    关于里氏替换原则的例子,最有名的是“正方形不是长方形”。当然,生活中也有很多类似的例子,例如,企鹅、鸵鸟和几维鸟从生物学的角度来划分,它们属于鸟类;但从类的继承关系来看,由于它们不能继承“鸟”会飞的功能,所以它们不能定义成“鸟”的子类。同样,由于“气球鱼”不会游泳,所以不能定义成“鱼”的子类;“玩具炮”炸不了敌人,所以不能定义成“炮”的子类等。

    下面以“几维鸟不是鸟”为例来说明里氏替换原则。

    【例2】里氏替换原则在“几维鸟不是鸟”实例中的应用。

    分析:鸟一般都会飞行,如燕子的飞行速度大概是每小时 120 千米。但是新西兰的几维鸟由于翅膀退化无法飞行。假如要设计一个实例,计算这两种鸟飞行 300 千米要花费的时间。显然,拿燕子来测试这段代码,结果正确,能计算出所需要的时间;但拿几维鸟来测试,结果会发生“除零异常”或是“无穷大”,明显不符合预期,其类图如图 1 所示。
     

    “几维鸟不是鸟”实例的类图
     

    package principle;
    public class LSPtest
    {
        public static void main(String[] args)
        {
            Bird bird1=new Swallow();
            Bird bird2=new BrownKiwi();
            bird1.setSpeed(120);
            bird2.setSpeed(120);
            System.out.println("如果飞行300公里:");
            try
            {
                System.out.println("燕子将飞行"+bird1.getFlyTime(300)+"小时.");
                System.out.println("几维鸟将飞行"+bird2.getFlyTime(300)+"小时。");
            }
            catch(Exception err)
            {
                System.out.println("发生错误了!");
            }
        }
    }
    //鸟类
    class Bird
    {
        double flySpeed;
        public void setSpeed(double speed)
        {
            flySpeed=speed;
        }
        public double getFlyTime(double distance)
        {
            return(distance/flySpeed);
        }
    }
    //燕子类
    class Swallow extends Bird{}
    //几维鸟类
    class BrownKiwi extends Bird
    {
        public void setSpeed(double speed)
        {
               flySpeed=0;
        }
    }

    程序的运行结果如下:

    如果飞行300公里:
    燕子将飞行2.5小时.
    几维鸟将飞行Infinity小时。


    程序运行错误的原因是:几维鸟类重写了鸟类的 setSpeed(double speed) 方法,这违背了里氏替换原则。正确的做法是:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为 0,但奔跑速度不为 0,可以计算出其奔跑 300 千米所要花费的时间。其类图如图 2 所示。
     

    “几维鸟是动物”实例的类图

     

    展开全文
  • 主要介绍了PHP面向对象五大原则之里氏替换原则(LSP),较为详细的分析了里氏替换原则(LSP)的概念、原理并结合实例形式分析了php里氏替换原则(LSP)的简单使用方法,需要的朋友可以参考下
  • 里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能。“多态”由继承语义实现。里氏替换原则...

    里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能。“多态”由继承语义实现。

    里氏替换原则包含以下4层含义:

    子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。

    子类中可以增加自己特有的方法。

    当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

    当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。

    现在我们可以对以上四层含义进行讲解。

    子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法

    在我们做系统设计时,经常会设计接口或抽象类,然后由子类来实现抽象方法,这里使用的其实就是里氏替换原则。子类可以实现父类的抽象方法很好理解,事实上,子类也必须完全实现父类的抽象方法,哪怕写一个空方法,否则会编译报错。

    里氏替换原则的关键点在于不能覆盖父类的非抽象方法。父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些规范,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

    在面向对象的设计思想中,继承这一特性为系统的设计带来了极大的便利性,但是由之而来的也潜在着一些风险。下面举例来说明继承的风险,我们需要完成一个两数相减的功能,由类A来负责。

    class A{

    public int func1(int a, int b){

    return a-b;

    }

    }

    public class Client{

    public static void main(String[] args){

    A a = new A();

    System.out.println("100-50="+a.func1(100, 50));

    System.out.println("100-80="+a.func1(100, 80));

    }

    }

    运行结果:

    100-50=50

    100-80=20

    后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类B来负责。即类B需要完成两个功能:

    两数相减。

    两数相加,然后再加100。

    由于类A已经实现了第一个功能,所以类B继承类A后,只需要再完成第二个功能就可以了,代码如下:

    class B extends A{

    public int func1(int a, int b){

    return a+b;

    }

    public int func2(int a, int b){

    return func1(a,b)+100;

    }

    }

    public class Client{

    public static void main(String[] args){

    B b = new B();

    System.out.println("100-50="+b.func1(100, 50));

    System.out.println("100-80="+b.func1(100, 80));

    System.out.println("100+20+100="+b.func2(100, 20));

    }

    }

    类B完成后,运行结果:

    100-50=150

    100-80=180

    100+20+100=220

    我们发现原本运行正常的相减功能发生了错误。原因就是类B在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类B重写后的方法,造成原本运行正常的功能出现了错误。在本例中,引用基类A完成的功能,换成子类B之后,发生了异常。在实际编程中,我们常常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合,组合等关系代替。

    展开全文
  • 里氏替换原则 1.定义   子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。   子类中可以增加自己特有的方法 1.2 UML类图 1.3 设计背景   有时候父类有多个子类,但在这些子类中有一个特例,如果不...

    里氏替换原则

    1.定义

      子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
      子类中可以增加自己特有的方法

    1.2 UML类图

    在这里插入图片描述

    1.3 设计背景

      有时候父类有多个子类,但在这些子类中有一个特例,如果不遵循里氏替换原则,重写了父类的方法,虽然实现了功能,会整个继承体系的可复用性会比较差,比如B继承了A,B重写了A的fun1()方法,C又继承了B,这个时候C使用fun1()方法,但使用的确是B的fun1(),而不是A的fun1()方法。按照继承设计的作用,子类是可以继承父类的方法和成员,减小代码冗余,增加复用。但是因为重写导致了复用性降低,C本来是想使用到A的fun1()方法,但是确没有使用到。

    public class A 
    {
         void fun1(int a, int b) 
         {
        	 int result = a-b;
        	 System.out.println(a + " - " + b + " = " + result);
         }
    }
    
    
    public class B extends A
    {
    	  /**
    	        * 子类重写了父类的fun1方法
    	  */
    	  void fun1(int a, int b)
          {
    			 int result = a+b;
    	    	 System.out.println(a + " + " + b + " = " + result);
          }
          void fun2(int a, int b)
          {
        	      int result = a*b;
    	    	 System.out.println(a + " * " + b + " = " + result);
          }
    }
    
    
    public class C extends B
    {
    	 void fun3(int a, int b)
         {
       	      int result = a/b;
    	    	 System.out.println(a + " / " + b + " = " + result);
         }
    }
    
    
    public class Test 
    {
        public static void main(String[] args) 
        {
        	A a = new A();
        	a.fun1(12, 4); //12 - 4 = 8
        	
        	B b = new B();
        	b.fun1(12, 4);//12 + 4 = 16
       
         	C c = new C();
          	c.fun1(12, 4);//12 + 4 = 16
    
         	
          	A ab = new B();
         	ab.fun1(12, 5);//12 + 5 = 17 运行时多态
    	}
    }
    
    
    

    1.4 实现思路

      如果既想满足里氏替换原则,又想满足这个子类的功能时,可以在子类中可以增加自己特有的方法fun2,当然也可以不走继承,使用关联,聚合,组合来解决问题。

    1.5 实现场景

    public class A 
    {
         public void fun1(int a, int b) 
         {
        	 int result = a-b;
        	 System.out.println(a + " - " + b + " = " + result);
         }
    }
    
    
    public class A1 
    {
    
    	  public void fun1(int a, int b)
          {
    		  A aObject = new A();//使用依赖关系 让A1可以使用A的方法
    		  aObject.fun1(a,b);
          }
    	  public void fun2(int a, int b)
    	  {
    		  int result = a+b;
    	      System.out.println(a + " + " + b + " = " + result);
    	  }
    } 
    
    public class B extends A
    {
    	
    	  /**
    	 * @param a
    	 * @param b
    	   *     增加加自己特有的方法fun2
    	 */
    	public void fun2(int a, int b)
          {
    			 int result = a+b;
    	    	 System.out.println(a + " + " + b + " = " + result);
          }
     
    }
    
    
    public class Test 
    {
        public static void main(String[] args) 
        {
        	A a = new A();
        	a.fun1(12, 4); //12 - 4 = 8
        	
        	B b = new B();
        	b.fun1(12, 4);//12 - 4 = 8
        	
        	b.fun2(12, 4);//12 + 4 = 16
        	
        	A1 a1 = new A1();
       
        	a1.fun1(12, 4);//12 - 4 = 8
        	
        	a1.fun2(12, 4);//12 + 4 = 16
         	
    
    	}
    }
    
    展开全文
  • 之前我们对设计模式的六大原则做了简单归纳,这篇博客是对里氏替换原则进行的举例说明。 里氏替换原则的意义子类可以扩展父类的功能,但不能改变父类原有的功能 继承机制的优点: 代码共享,减少创建类的工作量 ...
    之前我们对设计模式的六大原则做了简单归纳,这篇博客是对里氏替换原则进行的举例说明。
    

    里氏替换原则的意义

    子类可以扩展父类的功能,但不能改变父类原有的功能
    继承机制优点

    • 代码共享,减少创建类的工作量
    • 提高代码的重用性;
    • 子类可以形似父类,又异于父类;
    • 提高父类的扩展性,实现父类的方法即可随意而为;

    继承机制缺点

    • 继承是入侵性的(只要继承,就必须拥有父类的所有属性与方法);
    • 降低了代码的灵活性(子类拥有了父类的属性方法,会增多约束);
    • 增强了耦合性(当父类的常量、变量、方法被修改时,必需要考虑子类的修改)。

    违反里氏替换原则的反例子

    举例说明继承的风险,我们需要完成一个两数相减的功能,由类Subtraction来负责:
    这里写图片描述
    运行结果:
    这里写图片描述

    后来,我们需要增加一个新的功能:完成两数相加,然后再与100求和,由类Add来负责。所以类Add继承类Subtraction后,代码如下
    这里写图片描述

    我们发现原来运行正常的相减功能发生了错误。原因就是类Add在给方法起名时无意中重写了父类的方法,造成所有运行相减功能的代码全部调用了类Add的重写后的方法,造成原本运行正常的功能出现了错误。
    在本例中,使用Subtraction类完成的功能,换成子类Add之后,发生了异常。在实际编程中,我们常会通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的几率非常大。如果非要重写父类的方法,比较通用的做法是:原来的父类和子类都继承一个更通谷的基类,原来的继承关系去掉,采用依赖、聚合、组合等关系替代。

    展开全文
  • 里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用...
  • 里氏替换原则(Liskov Substitution Principle)在1988年,由麻省理工学院的一位姓里的女士提出的。指的是 任何基类可以出现的地方,子类一定可以出现 。 核心内容: 继承必须确保超类所拥有的性质在子类中仍然...
  • 一个违反里氏替换原则的例子、一个遵守里氏替换原则的例子。 // 绘制图形 void drawShape(Shape shape) { if (shape.type == Shape.Circle) { drawCircle((Circle) shape); } else if (shape.type == Shape....
  • 里氏替换原则

    万次阅读 2014-07-07 03:05:04
    里氏替换原则  这节中我们会聊聊里氏替换原则,聊它之前,我们先看看定义。  定义:如果对每一个类型为T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P ...
  • 里氏替换原则的定义 里氏替换原则(Liskov Substitution Principle,LSP)由麻省理工学院计算机科学实验室的里斯科夫(Liskov)女士在 1987 年的“面向对象技术的高峰会议”(OOPSLA)上发表的一篇文章《数据抽象和...
  • 里氏替换原则是面向对象设计的基本原则之一,主张使用“抽象(Abstraction)”和“多态(Polymorphism)”将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能,“多态”由继承语义实现。里氏...
  • 开闭原则与里氏替换原则

    千次阅读 2015-03-19 14:59:32
    2.里氏替换原则里氏替换原则是说,任何基类可以出现的地方,子类一定可以出现(只有当衍生类可以替换基类,软件单位的功能不受到影响,基类才能真正被复用,衍生类也能够在基类的基础上增加新的行为)。下面我们通过...
  • 设计原则(二)里氏替换原则(LSP)

    万次阅读 多人点赞 2015-11-29 11:03:47
    一、什么是里氏替换原则 里氏替换原则的严格表达是:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型...
  • 里氏替换原则(Liskov Substitution principle)是对子类型的特别定义的. 为什么叫里式替换原则呢?因为这项原则最早是在1988年,由麻省理工学院的一位姓里的女士(Barbara Liskov)提出来的。 里氏替换原则主要阐述...
  • 里氏代换原则 举例 分析

    千次阅读 2019-03-11 14:17:43
    里氏代换原则 定义:里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 目的:里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP是继承复用的基石,只有当衍生类可以...
  • 里氏替换原则 依赖倒置原则 接口分离原则 迪米特原则 1.单一职能原则 单一职责原则 其实就是开发人员经常说的”高内聚,低耦合” 也就是说,每个类或每个方法都只负责一件事情。 在设计模式中,所有的设计...
  • 1.单一原则(Single Responsibility Principle) :一个类或者一个方法只负责一项职责,尽量做到类的...2.里氏替换原则(LSP liskov substitution principle) :子类可以扩展父类的功能,但不能改变原有父类的功...
  • 接下来我们先来学习里氏替换原则里氏替换原则1、里氏替换原则英文全称是 Liskov Substitution Principle,缩写是LSP。LSP的第一种定义是:如果对每一个类型为S的对象O1,都有类型为T的对象O2,使得以T定义的所有...
  • 不使用里氏替换原则的解法: 代码实现: //具体类 class ReadFile { public void read(String fileName){ System.out.println("读取Excel文件"+fileName); } } class ReadDoc extends ReadFile{ //子类覆写父类的...
  • 如果对每一个类型为S的对象O1,都有类型为T的对象O2,使得以T定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。 简单的说就是所有引用基类的地方必须能透明地使用其...
  • 什么是里氏替换原则 英文:Liskov Substitution Principle 缩写 LSP。中文解释:子类对象能够替换程序中的父类对象,且不会改变父类的行文。 多态 定义:父类引用可以指向子类实例,子类重写或者继承父类的全部方法...
  • P3:里氏替换原则(LSP)

    2019-11-28 10:10:55
    里氏替换原则(Liskov Substitution Principle),简称LSP. 一、定义: 美国计算机科学Barbara Liskov提出定义如下: 如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1代换...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,840
精华内容 6,736
关键字:

里氏替换原则实例