举例解析Java的设计模式编程中里氏替换原则的意义
作者:卡奴达摩 发布时间:2021-06-30 18:37:17
里氏替换原则,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、for循环虽然所有循环结构都可以用 while 或者 do…while来表示,但 for 循环的出现,可使一些循环
- 操作步骤如下一、dropzone导入01.dropzone官网下载其插件压缩包并复制项目;02.将CSS和JS文件在HTML文件中引入;//
- 一、项目简述功能: 前后用户的登录注册,婚纱照片分类,查看,摄影师预 订,后台订单管理,图片管理等等。二、项目运行环境配置: Jdk1.8
- java web返回中文乱码ajax返回中文乱码问题 在浏览器按F12查看数据包可以看到charset为 iso-8859-1,这是spri
- HashMap的get()方法的NullPointerException今天写代码发现一个 bug,HashMap的 get() 方法一直报
- 迭代器是一种模式,它可以使得对于序列类型的数据结构的遍历行为与被遍历的对象分离,即我们无需关心该序列的底层结构是什么样子的。只要拿到这个对象
- IDEA安装后找不到.vmoptions文件在安装IDEA后在C盘的C:\Users\你的电脑用户名.IntelliJIdea2019.1\
- 目录MVC结构简介SpringMVC简介SpringMVC执行流程常用注解1. @Controller2. @ResponseBody3.
- 寻找到application.yml的读取的操作。从spring.factories 中查看到# Application Listeners
- 本文实例为大家分享了Java Swing实现扫雷源码的具体代码,供大家参考,具体内容如下先来看下效果运行时只需要创建一个GameWindow
- FastJson是阿里开源的一个高性能的JSON框架,FastJson数据处理速度快,无论序列化(把JavaBean对象转化成Json格式的
- 说明:本文记录如何在Idea下,利用Maven管理项目,并整合SSM(Spring + Spring MVC +Mybatis)框架,实现简
- 纯Java代码模拟Hibernate一级缓存原理,简单易懂。import java.util.ArrayList;import java.u
- 前言昨晚想在Android应用中增加一个int映射到String的字典表,使用HashMap实现的时候,Eclipse给出了一个警告,昨晚项
- rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统。它遵循Mozilla Public License开源协议,采用
- 前几天在这里分享了手写 sql 分页查询实现分页,现在来看看使用 mybatis 分页插件 pagehepler 来实现分页使用分页插件的原
- 前言WebJar官网:https://www.webjars.org/,对于任何与Servlet 3兼容的容器,WEB-INF/lib目录中
- 简介这篇文章我一直在纠结到底要不要写,不想写一来因为定时器用法比较简单,二来是面试中也不常问。后来还是决定写了主要是想把自己分析问题思路分享
- 一:SparkSQL1.SparkSQL简介Spark SQL是Spark的一个模块,用于处理结构化的数据,它提供了一个数据抽象DataFr