OOP 设计模式:接口与类的封装和重写(override)以及重载(overload)

2024-03-25 06:58

本文主要是介绍OOP 设计模式:接口与类的封装和重写(override)以及重载(overload),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要点

  • 子类是 extends 父类出来的

  • 子类会集成父类所有 public 类型的实例变量和方法,但不会集成父类所有 private 类型的变量和方法

  • 继承下来的属性可以被覆盖掉,但实例变量不能被覆盖掉

  • 类的多态性可以从方法override 和 overload 来体现

  • 一个类可以继承另外一个类或者实现多个接口


 

重写 Override

工程意义:重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!

如果需要扩展行为,就可以通过子类来实现,因此,继承是给类扩展和添加行为时的唯一工具。从继承开始说起。

type Rect = {x: number,y: number
}class Animal {protected flegCount:number;protected isAlive:boolean;protected color:string;protected position: Rect;constructor(){this.flegCount = 4;this.isAlive = true;this.color = "white"this.position = {x: 0,y: 0}}speak():string|null {return null;}
}class Dog extends Animal {speak():string|null {return "旺旺旺!";}
}class Cat extends Animal {speak():string|null {return "喵喵喵!";}
}

发生重写 Override - Animal 类 和 Cat 类中的 speak 方法的方法名和参数都一样

上面的 TypeScript 代码片段是一个基础的继承示例。Dog 和 Cat 类继承自 Animal,这意味着它们拥有 Animal 所有的属性和方法,我们不需要重新去定义它们,除非我们想覆盖原来的实现,就像上面的例子一样。继承允许我们将公共行为、状态(方法和属性)抽象到一个单独的地方,我们可以从那里(父类)提取。

const d1 = new Dog();
const c1 = new Cat();console.log(d1.speak());
console.log(c1.speak());

在线地址

继承的另一大好处是用父类的类型声明的变量也可以兼容来自子类的对象,主要体现在 Java,TypeScript 等强类型语言。比如:

let animals:Animal[] = [new Cat(), new Dog()]
animals.forEach( a => console.log(a.speak()));

在线地址

紧接着之前定义的类,这个例子声明了一组 Animal 类型的元素,包含了一个 Cat 和 一个 Dog。这是可行的,因为两个对象有相同的父类。同样,我们可以在安全地调用 speak 方法。因为这个方法已经在父类中定义了,我们知道所有的对象都有它。

重载 Overload

工程意义: 重载允许一个函数接受不同数量或类型的参数时,作出不同的处理

因为重载方法不是用来满足定义在父类(发生继承场景)的多态,所以重载的方法比较有扩展性。

class Overloads {uniqueID: number | string | null;constructor() {this.uniqueID = null;}addNums(a: string, b: string);addNums(a: number, b: number);addNums(a: string, b: number);addNums(a: number, b: string);addNums(a: number|string, b: number| string): number {if (typeof a === 'string') {a = Number(a);} if (typeof b === 'string') {b = Number(b);} return a + b;}setUniqueID(theID: string);setUniqueID(ssNumber: number) setUniqueID(value: number|string) {if (typeof value === 'number') {this.uniqueID = value} else if (typeof value === 'string') {const numberString = value + "";this.uniqueID = value}}}

发生重载 Overload - Overloads的同一个类中的多个 addNums 方法名相同,参数不同

执行测试

const o = new Overloads();
console.log('------- example1 ------')
console.log(o.addNums(1, 2));
console.log(o.addNums('3','5'));console.log('------- example2 ------')
console.log(o.setUniqueID('1'));
console.log(o.uniqueID)console.log(o.setUniqueID(2));
console.log(o.uniqueID)

在线地址

在 Java 中是这样子的

public class Overloads {String uniqueID;public int addNums(int a, int b) {return a + b;}public double addNums(double a, double b) {return a + b;}public void setUniqueID(String theID) {uniqueID = theID}public void setUniqueID(int ssNumber) {String numString = "" + ssNumber;setUniqueID(numString)}
}


 

重写与重载的区别

区别点

重载Overload方法

重写Overwrite方法

参数列表

必须修改

一定不能修改

返回类型

可以修改

一定不能修改

访问权限

可以修改

一定不能做更严格的限制

(可以降低限制,比如 protected 修改 public)


方法的重写(Overriding)和重载(Overloading)是面向对象中多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。

  • (1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。

  • (2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。

  • (3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

更严厉的权限描述

type Rect = {x: number,y: number
}class Animal {protected flegCount:number;protected isAlive:boolean;protected color:string;protected position: Rect;constructor(){this.flegCount = 4;this.isAlive = true;this.color = "white"this.position = {x: 0,y: 0}}public speak():string|null {return null;}
}class Dog extends Animal {speak():string|null {return "旺旺旺!";}
}class PrivateDog extends Animal {//Class 'PrivateDog' incorrectly extends base class 'Animal'.//Property 'speak' is protected in type 'PrivateDog' but public in type 'Animal'.protected speak():string|null {return "严厉的旺旺旺!";}
}const d = new Dog();
console.log(d.speak())

在线地址

抽象类 Abstract Class

工程意义:因为抽象类不能实例化对象,所以必须要有子类来实现它之后才能使用。这样就可以把一些具有相同属性和方法的组件进行抽象,这样更有利于代码和程序的维护

abstract class Department {constructor(public name: string) {}printName(): void {console.log('Department name: ' + this.name);}abstract printMeeting(): void; // 必须在派生类中实现
}class AccountingDepartment extends Department {constructor() {super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()}printMeeting(): void {console.log('The Accounting Department meets each Monday at 10am.');}generateReports(): void {console.log('Generating accounting reports...');}
}let department: Department; // 允许创建一个对抽象类型的引用
department = new Department(); // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
department.printName();
department.printMeeting();
department.generateReports(); // 错误: 方法在声明的抽象类中不存在

在线地址

什么时候用类或者接口

  1. 抽象类适合用来定义某个领域的固有属性,也就是本质,接口适合用来定义某个领域的扩展功能。

  2. 当需要为一些类提供公共的实现代码时,应优先考虑抽象类。因为抽象类中的非抽象方法可以被子类继承下来,使实现功能的代码更简单。

  3. 当注重代码的扩展性跟可维护性时,应当优先采用接口。

    1. ①接口与实现它的类之间可以不存在任何层次关系,接口可以实现毫不相关类的相同行为,比抽象类的使用更加方便灵活;

    2. ②接口只关心对象之间的交互的方法,而不关心对象所对应的具体类。接口是程序之间的一个协议,比抽象类的使用更安全、清晰。一般使用接口的情况更多。

案例1 接口:植物园内的水果,可以被拆下来,并且未来可以做成果汁

  

案例2 抽象类:狗狗可以有很多品种

 

 

案例3 接口:交通工具

 

案例4 抽象类:企业雇佣的员工分类(小时工,周薪员工等员工)

 

附录

  • 《Head First Java》 Head first java chapter 7 继承与多态_dengmu1918的博客-CSDN博客

  • 接口与抽象类的区别 深入理解Java的接口和抽象类 - Matrix海子 - 博客园

  • 何时使用接口(抽象类)? - dashuai的博客 - 博客园

这篇关于OOP 设计模式:接口与类的封装和重写(override)以及重载(overload)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/844181

相关文章

go中空接口的具体使用

《go中空接口的具体使用》空接口是一种特殊的接口类型,它不包含任何方法,本文主要介绍了go中空接口的具体使用,具有一定的参考价值,感兴趣的可以了解一下... 目录接口-空接口1. 什么是空接口?2. 如何使用空接口?第一,第二,第三,3. 空接口几个要注意的坑坑1:坑2:坑3:接口-空接口1. 什么是空接

SpringBoot中封装Cors自动配置方式

《SpringBoot中封装Cors自动配置方式》:本文主要介绍SpringBoot中封装Cors自动配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot封装Cors自动配置背景实现步骤1. 创建 GlobalCorsProperties

Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)

《Java导入、导出excel用法步骤保姆级教程(附封装好的工具类)》:本文主要介绍Java导入、导出excel的相关资料,讲解了使用Java和ApachePOI库将数据导出为Excel文件,包括... 目录前言一、引入Apache POI依赖二、用法&步骤2.1 创建Excel的元素2.3 样式和字体2.

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析

《MyBatis-Plus中Service接口的lambdaUpdate用法及实例分析》本文将详细讲解MyBatis-Plus中的lambdaUpdate用法,并提供丰富的案例来帮助读者更好地理解和应... 目录深入探索MyBATis-Plus中Service接口的lambdaUpdate用法及示例案例背景

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

MyBatis-Flex BaseMapper的接口基本用法小结

《MyBatis-FlexBaseMapper的接口基本用法小结》本文主要介绍了MyBatis-FlexBaseMapper的接口基本用法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具... 目录MyBATis-Flex简单介绍特性基础方法INSERT① insert② insertSelec