C#面向对象设计原则之里氏替换原则
作者:.NET开发菜鸟 发布时间:2022-08-27 23:59:22
里氏替换原则(LSP)
定义:在任何父类出现的地方都可以用它的子类类替换,且不影响功能。
解释说明:
其实LSP是对开闭原则的一个扩展,在OO思想中,我们知道对象是由一系列的状态和行为组成的,里氏替换原则说的就是在一个继承体系中,对象应该具有共同的外在特性,使用LSP时,如果想让我们的程序达到一个父类出现的地方都可以用它的子类来替换且不影响功能,那么这个父类也应该尽量声明出子类所需要的一些公共的方法,父类被子类替换之后,会比较顺利,那么为什么说它是对开闭原则的一个扩展呢?因为我们在开闭原则中说尽量使用接口和抽象类,当然这个抽象类和接口也应该尽量定义得完整,这样我们这个接口和抽象类会比较稳定,这样既符合了开闭原则也满足了里氏替换原则。
错误案例1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 里氏替换原则
{
/// <summary>
/// 鸟类
/// </summary>
public class Bird
{
/// <summary>
/// 吃的方法
/// </summary>
public void Eat()
{ }
/// <summary>
/// 飞的方法
/// </summary>
public void Fly()
{ }
}
/// <summary>
/// 定义一个企鹅类继承鸟类
/// </summary>
public class Penguin : Bird
{
}
public class Test
{
public static void ShowFly(Bird bird)
{
bird.Fly();
}
public static void Main()
{
ShowFly(new Penguin());
}
}
}
解释说明:
在上面的代码中,定义了一个鸟类,企鹅类继承自鸟类。鸟类里面有飞的方法,而企鹅不会飞,所以上面的代码违反了里氏替换原则。
错误案例2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 里氏替换原则
{
/// <summary>
/// 定义一个父类宠物类
/// </summary>
public class Pet
{
}
/// <summary>
/// 定义一个企鹅类继承自宠物类
/// </summary>
public class PenguinDemo : Pet
{
/// <summary>
/// 游泳的方法
/// </summary>
public void Swiming()
{
Console.WriteLine("可爱企鹅在游泳");
}
}
/// <summary>
/// 定义一个海豚类继承自宠物类
/// </summary>
public class Dolphin : Pet
{
/// <summary>
/// 玩游戏的方法
/// </summary>
public void PlayGame()
{
Console.WriteLine("神奇泡泡打砖块");
}
}
/// <summary>
/// 测试类
/// </summary>
public class Test
{
public static void ShowPlay(Pet pet)
{
if (pet is PenguinDemo)
{
//类型转换
PenguinDemo pen = (PenguinDemo)pet;
pen.Swiming();
}
if (pet is Dolphin)
{
//类型转换
Dolphin dol = (Dolphin)pet;
dol.PlayGame();
}
}
}
}
解释说明:
如果把河豚、企鹅当做宠物,我们可以定义一个宠物类,然后,让这些宠物继承这个类,我们知道每种宠物我们跟他玩耍的方式是不一样的。比如。企鹅有游泳的方法,河豚有游戏的方法,根据这个需求,我们设计一个系统,编写一个宠物类,让企鹅继承这个宠物类,在企鹅类里创建一个游泳的方法,这个方法不能放到宠物类里面,因为并不是所有宠物都会游泳。编写河豚类时,同样让他继承宠物类,在河豚类里面编写一个游戏的方法,这个时候客户端程序在使用宠物类和它的子类的时候,就需要做判断,具体是哪个子类,我们通过宠物类是无法调用具体的方法,要做一个判断和转型,如果在加一个狗类,狗类也会有一个独立的方法,要修改之前的代码(使用宠物类和它的子类的时候,要增加判断是狗类),这很明显不符合开闭原则,也不可能符合里氏替换原则,因为这里面的任何一个宠物都无法替换他的父类,因为他们的行为是不一样的,代码的可维护性和重用性很差!
代码下载链接:点此下载
来源:https://www.cnblogs.com/dotnet261010/p/7350046.html
猜你喜欢
- 利用闲余时间想自己搭建一个springboo
- 大家好,在这篇文章中,我们将学习如何添加动画,同时从一个页面到其他在 Flutter。我们将覆盖不同类型的动画和实现基本动画 Flutter
- springboot配置文件中属性变量引用@@这种属性应用方式是field_name=@field_value@。两个@符号是springb
- spring Cache注解和redis区别1.不支持TTL即不能设置过期时间 expires time,SpringCache 认为这是各
- 1 什么是cookie浏览器与WEB服务器之间是使用HTTP协议进行通信的,当某个用户发出页面请求时,WEB服务器只是简单的进行响应,然后就
- 根据数据库表名生成实体类公司用的jpa,没有用mybatis。所以也没有用mybatis自动生成。但有些数据库表字段太多,就想着一劳永逸了,
- 一、泛型的概念1.1 基础案例泛型在Java中的应用非常广泛,最常见则是在集合容器中,先看下基础用法:public class Generi
- Java中有四种权限修饰符publicprotected(default)private同一个类yesyesyesyes同一个包yesyes
- 一、准备工作1、确定电脑上已经成功安装jdk7.0以上版本2、win10操作系统3、maven安装包 下载地址:http://maven.a
- 声明式事务很方便,尤其纯注解模式,仅仅几个注解就能控制事务了思考:这些注解都做了什么?好神奇!@EnableTransactionManag
- 这篇文章主要介绍了Spring @Transactional注解失效解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 导入maven依赖<!-- https://mvnrepository.com/artifact/com.fasterxml.jack
- 一、概述xml整合第三方框架有两种整合方案:不需要自定义名空间,不需要使用Spring的配置文件配置第三方框架本身内容,例如:MyBatis
- 判断参数是否为空并作为查询条件@Override public Page<DemandEntity>
- Unity IPostBuildPlayerScriptDLLsUnity IPostBuildPlayerScriptDLLs是Unity
- 前言关于ThreadLocal (线程本地存储),从字面意思上看主要是存储一些本地变量,使它们能在一个线程内共用,与其他的线程进行数据隔离,
- graylog配置springboot配置依赖compile group: 'de.siegmar', name: '
- 在并发多线程的情况下,为了保证数据安全性,一般我们会对数据进行加锁,通常使用Synchronized或者ReentrantLock同步锁。S
- 在 Flutter 中使用图片是最基础能力之一。作为春节开工后的第一篇文章,17 做了精心准备,满满的都是干货!本文介绍如何在 Flutte
- 使用JAVA工程管理越来越多的jar包,担心导错了,多导了,漏导了怎么办?换一个IDE项目后项目会不会出一堆BUG,看的头皮发麻?自己写的代