golang如何实现“面向对象”

golang如何实现“面向对象”

 次点击
18 分钟阅读

封装

通常是指将数据(字段)和操作这些数据的功能(方法)组合在一起,同时控制数据的访问权限。

  1. 字段大小写

  2. 方法大小写

 package main
 
 import "fmt"
 
 type Person struct {
     name string // 私有字段
     Age  int    // 公有字段
 }
 
 // 通过指针传递结构体,能够修改字段
 func (p *Person) SetName(name string) {
     p.name = name // 通过指针修改私有字段
 }
 
 // 通过指针传递结构体,能够修改字段
 func (p *Person) SetAge(age int) {
     p.Age = age // 通过指针修改公有字段
 }
 
 // 通过值传递结构体,只能读取数据,不能修改
 func (p Person) GetName() string {
     return p.name // 读取私有字段
 }
 
 // 通过值传递结构体,读取公有字段
 func (p Person) GetAge() int {
     return p.Age // 读取公有字段
 }
 
 func main() {
     // 创建一个 Person 实例
     p := Person{Age: 25}
 
     // 通过方法修改公有字段和私有字段
     p.SetAge(30)      // 直接通过方法修改公有字段
     p.SetName("Alice") // 直接通过方法修改私有字段
 
     // 通过方法获取字段值
     fmt.Println("Name:", p.GetName()) // 输出:Name: Alice
     fmt.Println("Age:", p.GetAge())   // 输出:Age: 30
 
     // 注意,直接访问私有字段是非法的
     // fmt.Println(p.name)  // 编译错误:p.name undefined (cannot refer to unexported field or method name)
 
     // 通过指针修改字段
     pPointer := &p
     pPointer.SetAge(35)
     fmt.Println("Age after pointer modification:", p.GetAge()) // 输出:Age after pointer modification: 35
 
     // 通过值传递不会修改原数据
     newP := p
     newP.SetAge(40)
     fmt.Println("Age after value modification:", p.GetAge()) // 输出:Age after value modification: 35
 }

 

继承

隐式:golang里面的继承、不需要再跟结构体一样把接口嵌套进去、只需要实现接口里面的所有方法就可以了。

结构体继承

 // 通过嵌套结构体、来实现继承、
 // 1.嵌套了父结构体的子结构体可以使用父结构体的方法
 package main
 
 import "fmt"
 
 // 定义一个父结构体(可以理解为“父类”)
 type Animal struct {
     Name string
 }
 
 // 父结构体的方法
 func (a *Animal) Speak() {
     fmt.Println(a.Name + " makes a sound.")
 }
 
 // 定义子结构体(可以理解为“子类”)
 type Dog struct {
     Animal // 这里嵌入了父结构体Animal
 }
 
 // 主函数
 func main() {
     // 创建 Dog 对象,初始化时嵌入了 Animal 对象
     dog := Dog{Animal{Name: "Buddy"}}
     // 调用 Dog 的 Speak 方法(没有重写父类方法)
     dog.Speak() // 输出:Buddy makes a sound.
 }
 
 
 
 // 2.嵌套了父结构体的子结构体也重写父结构体的方法
 package main
 
 import "fmt"
 
 // 定义一个父结构体(可以理解为“父类”)
 type Animal struct {
     Name string
 }
 
 // 父结构体的一个方法
 func (a *Animal) Speak() {
     fmt.Println(a.Name + " makes a sound.")
 }
 
 // 定义子结构体(可以理解为“子类”)
 type Dog struct {
     Animal // 这里嵌入了父结构体Animal
 }
 
 // 子结构体的一个方法,重写了父结构体的Speak方法
 func (d *Dog) Speak() {
     fmt.Println(d.Name + " barks.")
 }
 
 func main() {
     // 创建Dog对象,初始化时嵌入了Animal对象
     dog := Dog{Animal{Name: "Buddy"}}
 
     dog.Speak() // 输出:Buddy barks.
     dog.Animal.Speak() // 输出:Buddy makes a sound.
 }

 

接口继承

  1. 接口嵌套:通过在一个接口中嵌套其他接口,来继承这些接口的所有方法。

  2. 隐式实现:Go 的类型通过实现接口的所有方法来“自动”实现该接口,不需要显式声明实现接口。

package main
 
 import "fmt"
 
 // 定义一个接口 Animal
 type Animal interface {
     Speak() string
 }
 
 // 定义一个接口 Mammal,继承 Animal 接口
 type Mammal interface {
     Animal  // 嵌套 Animal 接口
     Move() string
 }
 
 // 定义一个结构体 Dog
 type Dog struct{}
 
 // Dog 实现了 Animal 接口的 Speak 方法
 func (d Dog) Speak() string {
     return "Woof!"
 }
 
 // Dog 实现了 Mammal 接口的 Move 方法
 func (d Dog) Move() string {
     return "Dog moves on four legs."
 }
 
 func main() {
     // 创建 Dog 对象
     dog := Dog{}
 
     // 使用 Mammal 接口来引用 Dog
     var mammal Mammal = dog
 
     fmt.Println(mammal.Speak())  // 输出:Woof!
     fmt.Println(mammal.Move())   // 输出:Dog moves on four legs.
 }
 
 
 // 这里dog不仅实现了Mammal接口、也实现了Animal接口、因此也可以使用Animal接口的方法、例子如下
 var a Animal = dog{}
 fmt.Print(a.Speak())  

多态

多态就是不同结构体可以通过一个接口实现不同的行为
有一个父类(接口)
有子类、实现了父类的全部方法

例子1

package main
 
 import "fmt"
 
 // 定义一个接口
 type Speaker interface {
     Speak() string
 }
 
 // Dog 类型实现了 Speaker 接口
 type Dog struct{}
 
 func (d Dog) Speak() string {
     return "Woof!"
 }
 
 // Cat 类型实现了 Speaker 接口
 type Cat struct{}
 
 func (c Cat) Speak() string {
     return "Meow!"
 }
 
 // 函数接收一个 Speaker 接口类型的参数
 func Introduce(speaker Speaker) {
     fmt.Println(speaker.Speak())
 }
 
 func main() {
     d := Dog{}
     c := Cat{}
     
     Introduce(d) // 输出:Woof!
     Introduce(c) // 输出:Meow!
 }

 

例子2

 package main
 
 import "fmt"
 
 // 定义一个接口
 type Shape interface {
     Area() float64
 }
 
 // 定义 Rectangle 类型
 type Rectangle struct {
     Width, Height float64
 }
 
 // 实现 Shape 接口的 Area 方法
 func (r Rectangle) Area() float64 {
     return r.Width * r.Height
 }
 
 // 定义 Circle 类型
 type Circle struct {
     Radius float64
 }
 
 // 实现 Shape 接口的 Area 方法
 func (c Circle) Area() float64 {
     return 3.14 * c.Radius * c.Radius
 }
 
 // 打印形状的面积
 func PrintArea(s Shape) {
     fmt.Println("Area:", s.Area())
 }
 
 func main() {
     r := Rectangle{Width: 5, Height: 3}
     c := Circle{Radius: 4}
 
     // 通过接口统一处理不同类型
     PrintArea(r) // 输出:Area: 15
     PrintArea(c) // 输出:Area: 50.24
 }
  1. RectangleCircle 类型分别实现了 Shape 接口的 Area() 方法。

  2. PrintArea 函数接收一个 Shape 类型的参数,通过调用接口的方法 Area() 来统一计算不同形状的面积。

  3. 虽然 rc 是不同的类型,但它们都通过接口 Shape 被统一处理,这就是多态的表现。

前面的例子使用的都是值、不能修改结构体的字段、如果要修改结构体的字段、需要使用指针

 package main
 
 import "fmt"
 
 // 定义一个接口
 type Speaker interface {
     Speak() string
 }
 
 // Dog 类型实现了 Speaker 接口,方法接收者是指针类型
 type Dog struct {
     name string
 }
 
 func (d *Dog) Speak() string {
     return "Woof! My name is " + d.name
 }
 
 // 函数接收一个 Speaker 接口类型的参数
 func Introduce(speaker Speaker) {
     fmt.Println(speaker.Speak())
 }
 
 func main() {
     d := &Dog{name: "Rex"}
     Introduce(d) // 输出:Woof! My name is Rex
 }

© 本文著作权归作者所有,未经许可不得转载使用。