Golang面向对象编程(二)

news2024/11/26 22:37:54

文章目录

  • 封装
    • 基本介绍
    • 封装的实现
    • 工厂函数
  • 继承
    • 基本介绍
    • 继承的实现
    • 字段和方法访问细节
    • 多继承

封装

基本介绍

基本介绍

  • 封装(Encapsulation)是面向对象编程(OOP)中的一种重要概念,封装通过将数据和相关的方法组合在一起,形成一个称为类的抽象数据类型,只暴露必要的接口供外部使用。
  • 封装可以隐藏数据的实际实现细节,外部只能通过公共(public)接口来访问和修改数据,使得代码更加模块化和结构化,同时可以防止不恰当的访问和操作,提高数据的安全性。
  • 封装将相关的数据和方法组织在一起,形成了一个独立的单元,外部使用者只需关心公共接口,无需了解内部实现细节,简化了使用方式,提高了代码的可读性和可维护性。
  • 封装使得内部实现可以独立于外部接口进行修改,如果内部实现发生了变化,只需要确保公共接口的兼容性,而不会影响使用该类的其他代码,提供了更好的灵活性和可扩展性。

封装的实现

封装的实现

  • Go中的封装是通过命名约定和访问控制来实现的,而不像一些其他面向对象语言那样使用访问修饰符(如public、private、protected),因此开发者需要自觉遵守约定来保持封装的效果。
  • Go中通过结构体将相关的字段和方法组合在一起,并通过首字母大小写来控制其可访问性。结构体中的字段和方法使用大写字母开头表示公共的(可导出的),可以被其他包访问,而使用小写字母开头表示私有的(不可导出的),只能在当前包内使用。
  • Go中的封装更加宽泛,其封装的基本单元不是结构体而是包(package),包内的所有标识符(变量、函数、结构体、方法等)都通过首字母大小写来控制其可访问性

封装案例如下:

package model

import "fmt"

type Student struct {
	name   string
	age    int
	gender string
}

// 访问name字段
func (stu Student) GetName() string {
	return stu.name
}
func (stu *Student) SetName(name string) {
	stu.name = name
}

// 访问age字段
func (stu Student) GetAge() int {
	return stu.age
}
func (stu *Student) SetAge(age int) {
	stu.age = age
}

// 访问gender字段
func (stu Student) GetGender() string {
	return stu.gender
}
func (stu *Student) SetGender(gender string) {
	stu.gender = gender
}

// Student的其他方法
func (stu Student) Print() {
	fmt.Printf("student info: <name: %s, age: %d, gender: %s>\n",
		stu.name, stu.age, stu.gender)
}

使用上述包内结构体的案例如下:

package main

import (
	"go_code/OOP2/Encapsulate/model"
)

func main() {
	// var stu = model.Student{"Alice", 12, "女"} // 隐式赋值
	var stu model.Student
	stu.SetName("Alice")
	stu.SetAge(12)
	stu.SetGender("女")
	stu.Print() // student info: <name: Alice, age: 12, gender: 女>
}

注意: Go中无法对结构体中不可导出的字段进行隐式赋值,可以通过给结构体绑定对应的setter和getter方法对不可导出的字段进行访问和赋值。

工厂函数

工厂函数

如果结构体类型的首字母小写(不可导出),那么其他包将无法直接使用该结构体类型来创建实例,这时可以在包内提供对应可导出的工厂函数来创建实例并返回。如下:

package model

import "fmt"

type student struct {
	name   string
	age    int
	gender string
}

// 工厂函数
func NewStudent(name string, age int, gender string) *student {
	return &student{
		name:   name,
		age:    age,
		gender: gender,
	}
}

func (stu student) Print() {
	fmt.Printf("student info: <name: %s, age: %d, gender: %s>\n",
		stu.name, stu.age, stu.gender)
}

其他包通过调用包中可导出的工厂函数,即可创建对应不可导出的结构体实例。如下:

package main

import (
	"go_code/OOP2/Encapsulate/model"
)

func main() {
	var stu = model.NewStudent("Alice", 12, "女")
	stu.Print() // student info: <name: Alice, age: 12, gender: 女>
}

继承

基本介绍

基本介绍

  • 继承是面向对象编程中的一个重要概念,其允许一个类(子类/派生类)继承另一个类(父类/基类)的属性和方法,子类继承父类后可以直接访问和使用父类中字段和方法,同时可以添加自己的字段和方法。
  • 继承的主要优势在于代码复用,继承可以在不重复编写相似代码的情况下扩展现有的类,使代码更具可维护性和可扩展性。

继承示意图如下:

在这里插入图片描述

继承的实现

继承的实现

  • Go中的继承是通过嵌套匿名结构体的方式来实现的,如果一个结构体中嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体中的字段和方法,从而实现了继承的效果。

继承案例如下:

package main

import (
	"fmt"
)

// 基类
type Person struct {
	Name string
	Age  int
}
func (per Person) PrintInfo() {
	fmt.Printf("name = %s, age = %d\n", per.Name, per.Age)
}

// 派生类
type Student struct {
	Person    // 嵌套匿名结构体
	StudentId int
}
func (stu Student) Study() {
	fmt.Printf("student %d is studying...\n", stu.StudentId)
}

// 派生类
type Teacher struct {
	*Person   // 嵌套匿名结构体指针
	TeacherId int
}
func (tch Teacher) Teach() {
	fmt.Printf("teacher %d is teaching...\n", tch.TeacherId)
}

func main() {
	var stu = Student{Person{"Alice", 12}, 100}
	stu.PrintInfo() // name = Alice, age = 12
	stu.Study()     // student 100 is studying...

	var tch = Teacher{&Person{"Bob", 22}, 200}
	tch.PrintInfo() // name = Bob, age = 22
	tch.Teach()     // teacher 200 is teaching...
}

说明一下:

  • 在嵌套匿名结构体时,可以通过Type的方式嵌套匿名结构体,也可以通过*Type的方式嵌套匿名结构体指针。
  • 在创建结构体变量时,如果要通过字段名的方式初始化结构体字段,那么匿名结构体的字段名由匿名结构体的类型名充当。
  • 在结构体中嵌套匿名结构体后,可以通过结构体实例访问匿名结构体的字段和方法,但在访问时仍然遵循Go的命名约定和访问控制。如果被嵌套的匿名结构体的定义在其他包,那么通过结构体实例只能访问匿名结构体可导出的字段和方法。
  • 结构体中嵌入的匿名字段也可以是基本数据类型,在访问结构体中的匿名基本数据类型字段时,以对应基本数据类型的类型名作为其字段名。比如结构体中嵌入了一个匿名int字段,则通过结构体变量名.int的方式对其进行访问。

组合

在结构体中嵌套有名结构体属于组合关系,在访问组合的结构体字段和方法时,必须带上结构体的字段名。如下:

package main

import (
	"fmt"
)

// 车轮
type Wheel struct {
	Color string
	price int
}

// 自行车
type Bicycle struct {
	FrontWheel Wheel // 组合
	RearWheel  Wheel // 组合
	// ...
}
func (bc Bicycle) Print() {
	fmt.Printf("前轮<color:%s, price:%d元> 后轮<color:%s, price:%d元>\n",
		bc.FrontWheel.Color, bc.FrontWheel.price, bc.RearWheel.Color, bc.RearWheel.price)
}

func main() {
	var bc = Bicycle{
		FrontWheel: Wheel{"black", 100},
		RearWheel:  Wheel{"blue", 200},
	}
	bc.Print() // 前轮<color:black, price:100元> 后轮<color:blue, price:200元>
}

字段和方法访问细节

字段和方法访问细节

结构体字段和方法的访问流程:

  1. 先查看当前结构体类型中是否有对应的字段或方法,如果有则访问。
  2. 再查看结构体中嵌入的匿名结构体中是否有对应的字段或方法,如果有则访问。
  3. 继续查找更深层次嵌入的匿名结构体中是否有对应的字段或方法,如果有则访问,否则产生报错。

案例如下:

package main

import (
	"fmt"
)

// 基类
type Person struct {
	Name string
	Age  int
}
func (per Person) PrintInfo() {
	fmt.Printf("name = %s, age = %d\n", per.Name, per.Age)
}

// 派生类
type Student struct {
	Person
	StudentId int
}

func (stu Student) Study() {
	fmt.Printf("student %d is studying...\n", stu.StudentId)
}
func (stu Student) PrintInfo() {
	fmt.Printf("name = %s, age = %d, id = %d\n", stu.Name, stu.Age, stu.StudentId)
}

func main() {
	var stu = Student{Person{"Alice", 12}, 100}
	fmt.Printf("name = %s\n", stu.Name) // name = Alice
	stu.PrintInfo()                     // name = Alice, age = 12, id = 100
}

代码说明:

  • 在访问字段时,由于Student结构体中没有Name字段,因此Student变量.Name访问的是嵌套的匿名结构体Person中的Name字段。
  • 在访问方法时,由于Student结构体有PrintInfo方法,因此Student变量.PrintInfo()访问的是Student结构体的PrintInfo方法,而不是Person结构体的PrintInfo方法。

多继承

多继承

多继承指的是一个结构体中嵌套了多个匿名结构体,如果嵌套的多个匿名结构体中有相同的字段名或方法名,那么在访问时需要通过匿名结构体的类型名进行指明访问。如下:

package main

import (
	"fmt"
)

type Cat struct {
	Name string
	Age  int
}

type Dog struct {
	Name string
	Age  int
}

// 多继承
type Pet struct {
	Cat
	Dog
}

func main() {
	var pet = Pet{
		Cat: Cat{
			Name: "小猫",
			Age:  2,
		},
		Dog: Dog{
			Name: "小狗",
			Age:  3,
		},
	}
	fmt.Printf("cat name = %s\n", pet.Cat.Name) // cat name = 小猫
	fmt.Printf("dog name = %s\n", pet.Dog.Name) // dog name = 小狗
}

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

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

相关文章

进程间的IPC通信机制

一、介绍 进程与进程间的用户空间相互独立&#xff0c;内核空间共享。 1.传统的进程间通信机制 a.无名管道 pipe b.有名管道 fifo c.信号 signal 2.system V中的IPC对象 a.消息队列 message queue b.共享内存 shared memory c.信号灯集 semaphoare 3.可用于跨主机传输…

【C++ 】红黑树

1.1 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或 Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路 径会比其他路径长出俩倍&#xff…

Android的NDK开发中Cmake报缺少对应的x86的so文件

需要实现一个串口操作的命令。 供应商提供了2个so文件。 分别是 armeabi-v7a 和 arm64-v8a 添加到对应的cpp下。 在CMakeLists.txt里添加so文件 # 添加预编译的库 add_library(libxxx SHARED IMPORTED)# 设置库的路径 set_target_properties(libxxx PROPERTIES IMPORTED_…

OPT系列极速版远距离光数据传输器|光通讯传感器安装与调试方法

OPT系列极速版远距离光数据传输器|光通讯传感器使用红外激光通信&#xff0c;满足全双工 100M 带宽&#xff0c;通讯距离可达 300 米。能够快速&#xff0c;稳地传送数据&#xff0c;支持主流的工业控制总线&#xff08;Profinet&#xff0c;Ethercat 等&#xff09;&#xff1…

如何8步完成hadoop单机安装

前言 Hadoop是一个开源框架&#xff0c;用于存储和处理大规模数据集。 系统要求 Ubuntu 20.044GB&#xff08;建议8GB&#xff09;hadoop-3.3.6 步骤1&#xff1a;更新系统 打开终端并输入以下命令来更新您的系统&#xff1a; apt update 步骤2&#xff1a;安装Java Had…

浪潮信息企业级存储逆势增长 市场份额位列中国前二

2023年&#xff0c;中国企业级存储市场竞争激烈&#xff0c;在挑战重重之下&#xff0c;浪潮信息仍然实现逆势增长&#xff0c;销售额增幅达4.7%&#xff0c;市场份额相比2022年扩大0.6%&#xff0c;位列中国前二。另外&#xff0c;在高端和全闪存阵列细分市场&#xff0c;浪潮…

文件操作IO网络编程网络原理

​ 文件操作—IO 文件在计算机中可以代表很多东西 在操作系统中, 文件主要是指硬盘文件 硬盘主要分为机械硬盘和固态硬盘。机械硬盘通过磁头在旋转的磁盘上读取数据&#xff0c;适合顺序读取。而固态硬盘则使用闪存芯片来存储数据&#xff0c;没有机械部件&#xff0c;因此读…

进程创建-fork

demo1代码状态变迁 demo2代码输出到stdout使用管道 demo1 代码 #include <pthread.h> #include <iostream> #include <unistd.h> int main(int argc, char const *argv[]) {// 1.pid_t x fork();// 2.pid_t y fork();// 3.printf("%d %d\n", x…

电机及FOC算法介绍

一.电机概述 1.电机的简介 电机是一种可以在电能和机械能的之间相互转换的设备&#xff0c;其中发电机是将机械能转换为电能&#xff0c;电动机是将电能转换为机械能。发电机的主要用于产生电能&#xff0c;用途单一&#xff0c;但是电动机主要用于产生机械能&#xff0c;用途…

内容与图像一对多问题解决

场景复现 分析&#xff1a; 其实这是两给表&#xff0c;一个内容表&#xff0c;一个图片表&#xff0c;一对多的关系。 解决思路: 1. 先上传图片拿到图片的List集合ids&#xff0c;返回值是集合的ids&#xff0c;给到前端 2. 再添加内容表的数据生成了id&#xff0c;遍历查…

【Python探索之旅】初识Python

目录 发展史&#xff1a; 环境安装&#xff1a; 入门案例&#xff1a; 变量类型 标准数据类型 数字类型&#xff1a; 字符串&#xff1a; 全篇总结&#xff1a; 前言&#xff1a; Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设…

提升网络性能,解决网络故障,了解AnaTraf网络流量分析仪

在当今数字化时代&#xff0c;网络性能监测与诊断(Network Performance Monitoring and Diagnosis,NPMD)成为了企业和个人关注的焦点。随着网络流量不断增长&#xff0c;确保网络的稳定性和高效性变得更加重要。在这个领域&#xff0c;AnaTraf网络流量分析仪是您不可或缺的得力…

SqlServer2016安装

1、下载 下载地址&#xff1a; https://www.microsoft.com/en-us/server-cloud/products/sql-server-2016/ 或者 MSDN, 我告诉你 - 做一个安静的工具站 开发版下载地址&#xff1a;https://myprodscussu1.app.vssubscriptions.visualstudio.com/downloads KB2919442下载地址…

一、数据结构的三要素

数据的存储结构&#xff1a;顺序&#xff08;物理位置相邻&#xff09;、链式&#xff08;物理位置不相邻&#xff09;、索引&#xff08;还需要建立索引表&#xff09;、散列&#xff08;根据关键字直接计算出该元素的存储地址又称为hash存储&#xff09;、 时间复杂度&#x…

数据库——SQL SERVER(先学删库跑路)

目录 一&#xff1a;什么是数据库 二&#xff1a;为什么需要数据库 三&#xff1a;数据库的安装 四&#xff1a;学前必备知识 1. 数据库原理 2. 数据库与编程语言 3. 数据库与数据结构的区别 4. 连接 5. 有了编程语言为啥还要数据库 6. 初学者学习数据库的三个方面 …

数据结构与算法学习笔记六-二叉树的链式存储表示法和实现(C语言)

目录 前言 1.二叉树的链式存储 2.二叉链表的表示和实现 1.定义 2.创建 4.中序遍历二叉树 5.后序遍历二叉树 6.后序遍历二叉树 7.完整代码 前言 这篇博客主要介绍二叉树的链式存储结构。 1.二叉树的链式存储 上篇文章中介绍了二叉树的顺序存储结构&#xff0c;在最坏的…

MySQL_DDL语句

1.Data类临时数据的弊端 我们之前在将ServletJSP配合处理请求的过程中 数据库起到一个存取数据的作用 但是我们之前的案例中 数据是在Data类中临时定义的 并不是从数据库中获取的 这样做是不好的 因为每一次服务器关闭之后 那么部署在其上的类也会随着卸载 紧接着和类相挂钩的静…

DS高阶:B树系列

一、常见的搜索结构 1、顺序查找 时间复杂度&#xff1a;O(N) 2、二分查找 时间复杂度&#xff1a;O(logN) 要求&#xff1a;&#xff08;1&#xff09;有序 &#xff08;2&#xff09;支持下标的随机访问 3、二叉搜索树&#xff08;BS树&#xff09; 时间复杂…

通俗易通解读Restaking,潜力如何?(bitget钱包玩转)

关于 Restaking 再质押&#xff1a; 1. Restaking 在功能上&#xff0c;将以太坊安全性标准化&#xff0c;并将其“货币化”&#xff0c;Restaking 出售的就是以太坊的安全性&#xff0c;同时&#xff0c;将安全性用质押后的通证数量直观表现出来 2. Restaking 在经济机制上的逐…

NSSCTF | [第五空间 2021]WebFTP

注意看这里的题目标签&#xff0c;目录扫描&#xff0c;.git泄露。那么这道题虽然打开是一个登录的界面&#xff0c;但是并不是我们熟悉的爆破和SQL注入。 但是可以在题目标签上看到目录扫描&#xff0c;我们就用dirsearch扫一扫看看 python dirsearch.py -u http://node4.ann…