Go 中的 OOP - 多态性

Go 中的多态性是通过接口实现的。正如我们已经讨论过的,接口在 Go 中是隐式实现的。如果类型为接口中声明的所有方法提供定义,则该类型实现了接口。让我们看看 Go 中如何借助接口实现多态性。

使用接口的多态性

任何为接口的所有方法提供定义的类型都被称为隐式实现该接口。当我们稍后讨论多态性的示例时,这一点将会更加清楚。

接口类型的变量可以保存实现该接口的任何值。Go 中利用接口的这一特性来实现多态性。

让我们借助一个计算组织净收入的程序来了解 Go 中的多态性。为了简单起见,我们假设这个虚构的组织有来自两种项目的收入,即。固定计费时间和材料。该组织的净收入是根据这些项目的收入之和计算的。为了使本教程简单,我们假设货币是美元。它将使用 来表示int

我们首先定义一个接口Income

type Income interface {  calculate() intsource() string
}

上面定义的接口Income包含两个方法calculate(),分别计算并返回来源的收入和source()返回来源的名称。

接下来,让我们为FixedBilling项目类型定义一个结构体。

type FixedBilling struct {  projectName stringbiddedAmount int
}

FixedBilling项目有两个字段projectNamebiddedAmount,分别代表项目名称和组织对该项目投标的金额。

TimeAndMaterial结构将代表时间和材料类型的项目。

type TimeAndMaterial struct {  projectName stringnoOfHours  inthourlyRate int
}

TimeAndMaterial结构体具有三个字段名称projectNamenoOfHourshourlyRate

下一步是在这些结构类型上定义方法,计算并返回实际收入和收入来源。

func (fb FixedBilling) calculate() int {  return fb.biddedAmount
}func (fb FixedBilling) source() string {  return fb.projectName
}func (tm TimeAndMaterial) calculate() int {  return tm.noOfHours * tm.hourlyRate
}func (tm TimeAndMaterial) source() string {  return tm.projectName
}

就固定计费而言FixedBilling,收入只是项目的投标金额。该值是从接收者类型为FixedBilling的calculate()方法返回的

就时间和材料类型的项目,收入是noOfHourshourlyRate的乘积。该值是从接收者类型为TimeAndMaterial 的calculate()方法返回的

我们返回项目名称作为该方法的收入来源source()

由于 FixedBillingTimeAndMaterial结构都提供了接口的方法的定义,因此两个结构都实现了该接口。calculate()source()

让我们声明一个calculateNetIncome计算并打印总收入的函数。

func calculateNetIncome(ic []Income) {  var netincome int = 0for _, income := range ic {fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())netincome += income.calculate()}fmt.Printf("Net income of organization = $%d", netincome)
}

calculateNetIncome 上面的函数接受一个接口片段Income作为参数。它通过迭代切片并调用calculate()其每个项目的方法来计算总收入。它还通过调用source()方法显示收入来源。根据Income接口的具体类型,将调用不同的calculate()source()方法。这样我们就实现了函数的多态性

将来,如果组织添加了一种新的收入来源,该函数仍然可以正确计算总收入,而无需更改任何代码:)。

程序中唯一剩下的部分是主函数。

func main() {  project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}incomeStreams := []Income{project1, project2, project3}calculateNetIncome(incomeStreams)
}

main上面的函数中,我们创建了三个项目,两个类型为FixedBilling,一个类型为TimeAndMaterial。接下来,我们用这 3 个项目创建一个类型切片。由于每个项目都实现了该Income接口,因此可以将所有三个项目添加到 Income的切片中。最后,我们调用calculateNetIncome函数并将此切片作为参数传递。它将显示各种收入来源以及从中获得的收入。

这是完整的程序供您参考。

package mainimport (  "fmt"
)type Income interface {  calculate() intsource() string
}type FixedBilling struct {  projectName stringbiddedAmount int
}type TimeAndMaterial struct {  projectName stringnoOfHours  inthourlyRate int
}func (fb FixedBilling) calculate() int {  return fb.biddedAmount
}func (fb FixedBilling) source() string {  return fb.projectName
}func (tm TimeAndMaterial) calculate() int {  return tm.noOfHours * tm.hourlyRate
}func (tm TimeAndMaterial) source() string {  return tm.projectName
}func calculateNetIncome(ic []Income) {  var netincome int = 0for _, income := range ic {fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())netincome += income.calculate()}fmt.Printf("Net income of organization = $%d", netincome)
}func main() {  project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}incomeStreams := []Income{project1, project2, project3}calculateNetIncome(incomeStreams)
}

Run program in playground

该程序将输出

Income From Project 1 = $5000  
Income From Project 2 = $10000  
Income From Project 3 = $4000  
Net income of organization = $19000  

在上述计划中添加新的收入来源

假设该组织通过广告找到了新的收入来源。让我们看看添加这个新的收入流并计算总收入是多么简单,而无需对函数进行任何更改calculateNetIncome。由于多态性,这成为可能。

让我们首先定义Advertisement类型以及该calculate()source()的方法。

type Advertisement struct {  adName     stringCPC        intnoOfClicks int
}func (a Advertisement) calculate() int {  return a.CPC * a.noOfClicks
}func (a Advertisement) source() string {  return a.adName
}

Advertisement类型具有三个字段adName、、(CPC每次点击费用)和noOfClicks(点击次数)。广告总收入是CPCnoOfClicks的乘积。

让我们main稍微修改一下函数以包含这个新的收入流。

func main() {  project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}bannerAd := Advertisement{adName: "Banner Ad", CPC: 2, noOfClicks: 500}popupAd := Advertisement{adName: "Popup Ad", CPC: 5, noOfClicks: 750}incomeStreams := []Income{project1, project2, project3, bannerAd, popupAd}calculateNetIncome(incomeStreams)
}

我们制作了两个广告,即bannerAdpopupAd。该incomeStreams切片包含我们刚刚创建的两个广告。

这是添加广告后的完整程序。

package mainimport (  "fmt"
)type Income interface {  calculate() intsource() string
}type FixedBilling struct {  projectName  stringbiddedAmount int
}type TimeAndMaterial struct {  projectName stringnoOfHours   inthourlyRate  int
}type Advertisement struct {  adName     stringCPC        intnoOfClicks int
}func (fb FixedBilling) calculate() int {  return fb.biddedAmount
}func (fb FixedBilling) source() string {  return fb.projectName
}func (tm TimeAndMaterial) calculate() int {  return tm.noOfHours * tm.hourlyRate
}func (tm TimeAndMaterial) source() string {  return tm.projectName
}func (a Advertisement) calculate() int {  return a.CPC * a.noOfClicks
}func (a Advertisement) source() string {  return a.adName
}
func calculateNetIncome(ic []Income) {  var netincome int = 0for _, income := range ic {fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())netincome += income.calculate()}fmt.Printf("Net income of organization = $%d", netincome)
}func main() {  project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}bannerAd := Advertisement{adName: "Banner Ad", CPC: 2, noOfClicks: 500}popupAd := Advertisement{adName: "Popup Ad", CPC: 5, noOfClicks: 750}incomeStreams := []Income{project1, project2, project3, bannerAd, popupAd}calculateNetIncome(incomeStreams)
}

Run program in playground

上述程序将输出,

Income From Project 1 = $5000  
Income From Project 2 = $10000  
Income From Project 3 = $4000  
Income From Banner Ad = $1000  
Income From Popup Ad = $3750  
Net income of organization = $23750  

calculateNetIncome您可能已经注意到,尽管我们添加了新的收入来源,但我们并未对该功能进行任何更改。它只是因为多态性而起作用。由于新Advertisement类型也实现了该Income接口,因此我们能够将其添加到incomeStreams切片中。该calculateNetIncome函数无需任何更改即可运行,因为它能够调用该类型的calculate()source()方法。

本教程到此结束。祝你有美好的一天。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/129722.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

玩转AIGC:如何选择最佳的Prompt提示词?

🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 &a…

面试经典150题——Day30

文章目录 一、题目二、题解 一、题目 209. Minimum Size Subarray Sum Given an array of positive integers nums and a positive integer target, return the minimal length of a subarray whose sum is greater than or equal to target. If there is no such subarray, …

周赛369(位运算、分类讨论、记忆化搜索==>动态规划、树形DP)

文章目录 周赛369[2917. 找出数组中的 K-or 值](https://leetcode.cn/problems/find-the-k-or-of-an-array/)位运算模拟 [2918. 数组的最小相等和](https://leetcode.cn/problems/minimum-equal-sum-of-two-arrays-after-replacing-zeros/)分类讨论 [2919. 使数组变美的最小增量…

docker部署MySQL服务

部署 MySQL8.0.35社区版 1.下载镜像 docker pull container-registry.oracle.com/mysql/community-server:8.0.35 查看镜像 docker images 2. 启动MySQL服务器实例 docker run --namemysql8 --restart on-failure -p 3309:3306 -d container-registry.oracle.com/mysql/comm…

探索C++中的不变之美:const与构造函数的深度剖析

W...Y的主页😊 代码仓库分享💕 🍔前言: 关于C的博客中,我们已经了解了六个默认函数中的四个,分别是构造函数、析构函数、拷贝构造函数以及函数的重载。但是这些函数都是有返回值与参数的。提到参数与返回…

GPT的使用和反思

GPT的场景 GPT(Generative Pre-trained Transformer)是一种基于Transformer结构的语言模型,它在自然语言处理领域有广泛的应用。一般情况下,以下几种情况会使用GPT: 文本生成:GPT可以生成自然流畅的文本&a…

零日漏洞预防

零日漏洞,是软件应用程序或操作系统(OS)中的意外安全漏洞,负责修复该漏洞的一方或供应商不知道该漏洞,它们仍然未被披露和修补,为攻击者留下了漏洞,而公众仍然没有意识到风险。 零日攻击是如何…

Unity中Shader的烘培分支的判断

文章目录 前言一、上一篇文章中所需要的 lightmapUV 只有在烘焙时才会使用1、查看帮助文档后,Unity中判断烘培是否开启,使用的是LIGHTMAP_ON2、我们在 appdata 和 v2f 中,定义第二套UV 前言 Unity中Shader的烘培分支的判断,基于上…

【Linux网络编程_TCP/UDP_字节序_套接字 实现: FTP 项目_局域网聊天项目 (已开源) 】.md updata:23/11/03

文章目录 TCP/UDP对比端口号作用字节序字节序转换api套接字 socket实现网络通讯服务端 逻辑思路demo: 满血版双方通讯/残血版多方通讯服务端 demo客户端 demo FTP 项目实现sever demo:client demo: 局域网多方通讯 配合线程实现sever demo:client demo: TCP/UDP对比…

Django使用APSchedule实现简单定时任务

一、环境依赖 系统:windows10 python: python3.9.0 djnago3.2.0 APScheduler3.10.1 二、django中的配置 1、创建utils包,在包里面创建schedulers包 utils/schedulers/task.py #1、设置 Django 环境,就可以导入项目的模型类这些了 imp…

JDBC数据库连接---附通用的CRUD类

文章目录 JDBC数据库连接1 导包2 编写配置文件3 编写连接数据库代码4 测试工具类5 附加1 通用的CRUD类2 测试CURD类3 测试 JDBC数据库连接 本篇文章以 MySQL 数据库为例,若要切换其他数据库,只需修改 resource文件夹中的 jdbc.properties 配置文件即可。…

解决mysql数据库root用户看不到库

第一种方式: 1.首先停止MySQL服务:service mysqld stop 2.加参数启动mysql:/usr/bin/mysqld_safe --skip-grant-tables & 然后就可以无任何限制的访问mysql了 3.root用户登陆系统:mysql -u root -p mysql 4.切换数据库&#…

【Flutter】Flutter 动画深入解析(1):掌握 AnimationController 的使用

【Flutter】Flutter 动画深入解析(1):掌握 AnimationController 的使用 文章目录 一、前言二、AnimationController 简介三、AnimationController 的主要功能四、Ticker 提供者五、AnimationController 的生命周期六、与 AnimationController 一起使用的 Future七、实际业务…

PS2024免费磨皮滤镜Portraiture插件下载

Portraiture 4是一款适用于LR的人像智能磨皮美化滤镜插件,操作简便、省去了选择蒙版和逐步像素处理的繁琐流程,帮助您实现高效的肖像修饰。快速对照片中皮肤、头发、眉毛等部位进行美化,无需手动调整,大大提高P图效率。全新4版本&…

C#线程学习,线程的创建,线程的暂停,线程的锁lock,Monitor,线程使用中的注意事项(一)

C#线程学习,线程的创建,线程的暂停,线程的锁lock,Monitor,线程使用中的注意事项(一) 八股文 线程和进程 进程是指程序的一次执行过程,而线程是指进程中执行的一条单一逻辑控制流。 进程是由多…

Redis ACL安全策略详解

一,redis新特性ACL安全策略介绍 在 Redis6 之前的版本,我们只能使用 requirepass 参数给 default 用户配置登录密码,同一个 redis 集群的所有开发都共享 default 用户,难免会出现误操作把别人的 key 删掉或者数据泄露的情况。 因此…

基于单片机的智能鱼缸控制系统的设计与实现

收藏和点赞,您的关注是我创作的动力 文章目录 概要 一、开发技术和原理的相关知识2.1开发设计目标2.2 开发设计使用技术和原理2.2.1嵌入式技术2.2.2传感器技术 二、基于单片机的智能鱼缸控制系统的总体设计3.1智能鱼缸控制系统的基本组成3.1.1系统的构成部分3.2需求…

高校动物实验室建设要点

高校动物实验室应按照合理的规划布局进行设计,以便满足实验教学和科学研究的需求。如区分功能区域。根据实验室的不同功能,划分出饲养区、实验区、准备区和储存区等功能区域。动物房应根据不同种类动物的需求进行布置,确保各种动物的饲养条件…

uni-app 解决钉钉小程序日期组件uni-datetime-picker不兼容ios问题

最近在使用uni-app开发 钉钉小程序 ,遇到一个ios的兼容性问题 uni-datetime-picker 组件在模拟器上可以使用,在真机上不生效问题 文章目录 1. 不兼容的写法,uni-datetime-picker 不兼容IOS2. 兼容的写法,使用 dd.datePicker 实现。…

【ZMQ】ZMQ/ZeroMQ简介、三种消息模式demo程序

ZMQ/ZeroMQ简介、三种消息模式demo程序 一、什么是ZMQ二、ZMQ的特点三、Demo程序代码3.1 发布-订阅模式(P/S)demo3.2 请求-应答模式(REQ/RES)demo3.3 推拉模式(P/P)demo 一、什么是ZMQ ZeroMQ(…