• ch17、面向对象编程-扩展与复用


    ch17、面向对象编程 - 扩展与复用

    1、扩展与复用(即结构体内嵌)

    Go不支持继承,通过组合(内嵌)的方式来实现(没有override的特性,Go本身不支持隐式类型转换,对于内嵌来说显式转换也不行)

    与其它主要编程语言的差异:

    • 不支持子类替换
    • 子类并不是真正继承了父类的方法(“duck type”)
    • 父类定义的方法无法访问子类的数据和方法

    内嵌:B嵌入A,则A具备B的所有字段和行为(方法)

    type B struct{
        X,Y int
    }
    
    type A struct{
        B
        Z int
    }
    
    // 则A具备有X,Y,Z字段
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    匿名嵌入结构体实例

    package extension
    
    import (
    	"fmt"
    	"testing"
    )
    
    type Pet struct {
    }
    
    func (p *Pet) Speak() {
    	fmt.Print("...")
    }
    
    func (p *Pet) SpeakTo(host string) {
    	p.Speak()
    	fmt.Println(" ", host)
    }
    
    type Dog struct {
    	Pet
    }
    
    func (d *Dog) Speak() {
    	fmt.Println("wang!")
    }
    
    func TestDog(t *testing.T) {
    	dog := new(Dog)
    	dog.Speak()
    	dog.SpeakTo("Chao")
    }
    /*
    output:
    wang!
    ...  Chao
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    嵌入的类型可以是指针,此时,字段和方法间接的来自于所指向的对象(匿名嵌入结构体实例指针):

    package extension
    
    import (
    	"fmt"
    	"testing"
    )
    
    type Pet struct {
    }
    
    func (p *Pet) Speak() {
    	fmt.Print("...")
    }
    
    func (p *Pet) SpeakTo(host string) {
    	p.Speak()
    	fmt.Println(" ", host)
    }
    
    type Cat struct {
    	*Pet
    }
    
    func (c *Cat) Speak() {
    	fmt.Println("miaomiao!")
    }
    
    func (c *Cat) toPet(p *Pet, s string) {
    	p.SpeakTo(s)
    }
    
    func TestCat(t *testing.T) {
    	cat := new(Cat)
    	cat.Speak()
    	cat.SpeakTo("Chao")
    	cat.toPet(&Pet{}, "cat miaomiao")
    }
    /*
    output:
    miaomiao!
    ...  Chao
    ...  cat miaomiao
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 继承结构中出现重名情况, 采用就近原则
    package main
    
    import "fmt"
    
    type Person struct {
    	name string // 属性重名
    	age  int
    }
    type Student struct {
    	Person
    	name  string // 属性重名
    	score int
    }
    
    func main() {
    	s := Student{Person{"zs", 18}, "ls", 99}
    
    	fmt.Println(s.Person.name) // zs
    	fmt.Println(s.name)        // ls
    	//fmt.Println(s.Person.age)
    	fmt.Println(s.age) // 两种方式都能访问
    	fmt.Println(s.score)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    2、Go嵌入式"继承"机制的局限

    不支持Overriding Methods。

    package main
    
    import (
    	"fmt"
    )
    
    type Pet struct {
    	name string
    }
    
    type Dog struct {
    	Pet
    	Breed string
    }
    
    func (p *Pet) Play() {
    	fmt.Println(p.Speak())
    }
    
    func (p *Pet) Speak() string {
    	return fmt.Sprintf("my name is %v", p.name)
    }
    
    func (p *Pet) Name() string {
    	return p.name
    }
    
    func (d *Dog) Speak() string {
    	return fmt.Sprintf("%v and I am a %v", d.Pet.Speak(), d.Breed)
    }
    
    func main() {
    	d := Dog{Pet: Pet{name: "spot"}, Breed: "pointer"}
    	fmt.Println(d.Name())
    	fmt.Println(d.Speak())
    	d.Play() // 依然会调用pet的Speak,而不是dog的Speak,即嵌入的方法不会被
    }
    /*
    output:
    spot
    my name is spot and I am a pointer
    my name is spot
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    不存在Subtyping(没有多态)。

    在Java中,Dog继承自Pet,那么Dog类型就是Pet子类。这意味着在任何需要调用Pet类型的场景都可以使用Dog类型替换。这种关系称作多态性,但Go的结构体类型不存在这种机制。

    package main
    
    import (
    	"fmt"
    )
    
    type Pet struct {
    	speaker func() string
    	name    string
    }
    
    type Dog struct {
    	Pet
    	Breed string
    }
    
    func NewPet(name string) *Pet {
    	p := &Pet{
    		name: name,
    	}
    	p.speaker = p.speak
    	return p
    }
    
    func (p *Pet) Play() {
    	fmt.Println(p.Speak())
    }
    
    func (p *Pet) Speak() string {
    	return p.speaker()
    }
    
    func (p *Pet) speak() string {
    	return fmt.Sprintf("my name is %v", p.name)
    }
    
    func (p *Pet) Name() string {
    	return p.name
    }
    
    func NewDog(name, breed string) *Dog {
    	d := &Dog{
    		Pet:   Pet{name: name},
    		Breed: breed,
    	}
    	d.speaker = d.speak
    	return d
    }
    
    func (d *Dog) speak() string {
    	return fmt.Sprintf("%v and I am a %v", d.Pet.speak(), d.Breed)
    }
    
    func Play(p *Pet) {
    	p.Play()
    }
    
    func main() {
    	d := NewDog("spot", "pointer")
    	fmt.Println(d.Name())
    	fmt.Println(d.Speak())
    	Play(d) //  cannot use d (type *Dog) as type *Pet in argument to Play
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    但是,可以通过接口类型中存在子类化来实现多态机制!

    package main
    
    import (
    	"fmt"
    )
    
    type Pet interface {
    	Name() string
    	Speak() string
    	Play()
    }
    
    type pet struct {
    	speaker func() string
    	name    string
    }
    
    type Dog interface {
    	Pet
    	Breed() string
    }
    
    type dog struct {
    	pet
    	breed string
    }
    
    func NewPet(name string) *pet {
    	p := &pet{
    		name: name,
    	}
    	p.speaker = p.speak
    	return p
    }
    
    func (p *pet) Play() {
    	fmt.Println(p.Speak())
    }
    
    func (p *pet) Speak() string {
    	return p.speaker()
    }
    
    func (p *pet) speak() string {
    	return fmt.Sprintf("my name is %v", p.name)
    }
    
    func (p *pet) Name() string {
    	return p.name
    }
    
    func NewDog(name, breed string) *dog {
    	d := &dog{
    		pet:   pet{name: name},
    		breed: breed,
    	}
    	d.speaker = d.speak
    	return d
    }
    
    func (d *dog) speak() string {
    	return fmt.Sprintf("%v and I am a %v", d.pet.speak(), d.breed)
    }
    
    func Play(p Pet) {
    	p.Play()
    }
    
    func main() {
    	d := NewDog("spot", "pointer")
    	fmt.Println(d.Name())
    	fmt.Println(d.Speak())
    	Play(d)
    }
    /*
    output:
    spot
    my name is spot and I am a pointer
    my name is spot and I am a pointer
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    参考文档:

    Go中的面向对象 - “继承”

    在线运行结果

    3、如何分析一个类

    • 一般名词都是类(名词提炼法)
      • 飞机发射两颗炮弹摧毁了8辆装甲车
    飞机
    炮弹
    装甲车
    
    • 1
    • 2
    • 3
    • 隔壁老王在公车上牵着一条叼着热狗的草泥马
    老王
    热狗
    草泥马
    
    • 1
    • 2
    • 3
  • 相关阅读:
    股票量化系统QTYX选股框架实战案例集|华为补涨龙三连板打板进,套利8个点离场-230908...
    Linux MQTT智能家居(源码使用分析)
    图像增强软件分享
    windows自动切换深色模式(夜晚模式)
    C++结构型模式-组合模式
    IP地址c++题解
    【无标题】
    数据分析_数据分析思维(1)
    【Try to Hack】john哈希破解工具
    环境主题静态HTML网页作业作品 大学生环保网页设计制作成品 简单DIV CSS布局网站
  • 原文地址:https://blog.csdn.net/u012558127/article/details/126133165