设计模式之里氏替换原则C++实现

2022-06-16 14:33:55 浏览数 (1)

里氏替换原则: 子类可以扩展父类的功能,但不能改变父类原有的功能,不要重写父类的方法。

原因:如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差。

实现思想:取消原来的继承关系,重新设计它们之间的关系。

具体示例:

燕子会飞,几维鸟不会飞,其速度为0,计算两者飞行速度。UML类图如下

第一步:添加 bird.h

代码语言:javascript复制
#pragma once//这个是必须的,不然子类没法引用的
#include <iostream>
using namespace std;
class Bird
{
    public:
        void setspeed(double speed){bird_speed=speed;}
        double gettime(double dis){return (dis/bird_speed);}
    public:
        double bird_speed;
};

第二步:添加swallow.h

代码语言:javascript复制
#include "bird.h"
class Swallow:public Bird
{
};

第三步:添加 brownkiwi.h

代码语言:javascript复制
#include "bird.h"
class BrownKiwi: public Bird
{
    public:
        void setspeed(double speed){bird_speed=0;}
};

第四步:实现 main.cpp

代码语言:javascript复制
#include "swallow.h"
#include "brownkiwi.h"
#include "bird.h"
#include <csignal>
#include <cmath>
#include "notbird_brownkiwi.h"
//异常处理
void output(double x,double y)
{
    if( isinf(x))
        throw x;
    if(isinf(y))
        throw y;
    if(!isinf(x) && !isinf(y))
    {
        cout<<"燕子飞行了:"<<x<<" 小时"<<endl;
        cout<<"几维鸟飞行了:"<<y<<" 小时"<<endl;
    }
}

int main()
{  
    //父类指针指向子类对象
    //这样定义不对
   // Bird *bird1=new Swallow();
  //  Bird *bird2=new BrownKiwi();
  
   //父类指针指向子类对象
   /* Swallow bird1_;
    BrownKiwi bird2_;
    Bird* bird1=&bird1_;
    Bird* bird2=&bird2_;
      //转化为父类对象
      Bird _bird2=*bird2;*/

   //定义子类对象
   Swallow* bird1=new Swallow();
  BrownKiwi* bird2=new BrownKiwi();//
 
    bird1->setspeed(120);
    bird2->setspeed(120);
    cout<<"飞行300公里"<<endl;
   //  _bird2.setspeed(120);
    double x=bird1->gettime(300);
    double y=bird2->gettime(300);
    try
    {
           output(x,y);
       //  cout<<"几维鸟飞行了:"<<_bird2.gettime(300)<<" 小时"<<endl;
    }
    catch (double)
    {
        std::cerr << "除数是0! 发生错误!" << std::endl;
    }
   return 0;
}

结果显示:

运行错误:几维鸟类重写了鸟类的 setspeed方法,违背了里氏替换原则。

正确做法:取消几维鸟原来的继承关系,定义鸟和几维鸟的更一般的父类,如动物类,它们都有奔跑的能力。几维鸟的飞行速度虽然为0,但奔跑速度不为 0。修改后的UML类如下所示。

第五步:添加 anmial.h

代码语言:javascript复制
#pragma once//这个是必须的,不然子类没法引用的

class Animal
{
    public:
        void setspeed(double speed){this->_speed=speed;}
        double gettime(double dis){return dis/_speed;}
    private:
        double _speed;
};

第六步: 重新定义notbird_brownkiwi.h

代码语言:javascript复制
#include "animal.h"
class NotBirdBrownKiwi: public Animal
{
};

第七步: 修改 main.cpp

代码语言:javascript复制
 NotBirdBrownKiwi* bird2=new  NotBirdBrownKiwi();//调用的是子类的方法

结果显示:

0 人点赞