加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

开闭原则与里氏替换原则

发布时间:2020-12-13 22:34:17 所属栏目:百科 来源:网络整理
导读:1.开闭原则 是面向对象设计的基本原则之一,是“可复用设计”的基础,它的主要原则是:对扩展开放,对修改关闭;意思就是我们改变一个软件时。应该通过扩展方式来改变软件,而不是修改原有的代码。 2.里氏替换原则 里氏替换原则是说,任何基类可以出现的地方

1.开闭原则

是面向对象设计的基本原则之一,是“可复用设计”的基础,它的主要原则是:对扩展开放,对修改关闭;意思就是我们改变一个软件时。应该通过扩展方式来改变软件,而不是修改原有的代码。

2.里氏替换原则

里氏替换原则是说,任何基类可以出现的地方,子类一定可以出现(只有当衍生类可以替换基类,软件单位的功能不受到影响,基类才能真正被复用,衍生类也能够在基类的基础上增加新的行为)。


下面我们通过建一个项目,简单实现一下,假如一个学生养了两只动物,一只狗一只猫,需要进行喂食(过程中导入头文件的操作省略,方法在.h中的声明也省略,请自行添加)

1.需要建立的类有:

根视图MainViewController,负责整体的调用与测试

继承自NSobject的类Animal和继承自Animal类的子类Cat和Dog

继承自NSObject的类Student

2.在Animal类中实现一个方法:

-(void)eat
{
    NSLog(@"动物吃不同的东西");
}

然后在其子类Cat和Dog中重写父类方法:
-(void)eat
{
    [super eat];
    NSLog(@"猫吃鱼");
}

-(void)eat
{
    [super eat];
    NSLog(@"狗吃骨头");
}

当然也要在Cat和Dog的头文件中引入 -( void )eat;不然Cat和Dog实例化的对象无法调用此方法

3.如果不使用开闭和里氏替换,则要在Student类中实现两个喂养方法(导入Cat和Dog的头文件):

-(void)feedCat:(Cat*)cat
{
    NSLog(@"学生喂猫了");
    [cat eat];
}

-(void)feedDog:(Dog*)dog
{
    NSLog(@"学生喂狗了");
    [dog eat];
}

4.现在在MainViewController中的viewDidLoad中调用是这样的:
Student *stu=[[Student alloc]init];
    Dog *dog=[[Dog alloc]init];
    Cat *cat=[[Cat alloc]init];
    [stu feedCat:cat];
    [stu feedDog:dog];

这种基本实现方式是可以的,也能实现,但是如果学生又喂了一只乌龟,则又需要在Student中添加给乌龟喂食的方法,这种频繁修改源代码的方式不太可取,下面我们用上开闭原则和里氏替换原则,重复3和4的步骤;

3.只需要在Student类中实现一个喂养方法(导入Animal的头文件):

-(void)feed:(Animal*)animal
{
    NSLog(@"学生喂动物了");
    [animal eat];
}
4.在MainViewController中的viewDidLoad中需要这样调用:
Student *stu=[[Student alloc]init];
    Animal *aCat=[[Cat alloc]init];
    Animal *aDog=[[Dog alloc]init];
    [stu feed:aCat];
    [stu feed:aDog];

这样即使学生再喂养N只动物,Student里面的代码也不需要再去修改(满足了上面所说的开闭原则),大大减少了工作量,保持了代码的完整性;

这两行

Animal *aCat=[[Cat alloc]init];
Animal *aDog=[[Dog alloc]init];
就是里氏替换,其本质就是用子类去实例化父类声明的对象(即父类的指针指向子类开辟内存),然后调用子类内部的方法等。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读