前面我们已经将GO语言中各种类型,给大家讲解完毕了,那么接下来要给大家讲解的是面向对象编程思想。
在讲解具体面向对象编程之前,先说一下面向过程编程。我们前面学习都是面向过程的一种编程思想,接下来可以从生活中理解面向过程:
如果我们自己来修汽车,应该有哪些步骤呢?
第一步:找工具
第二步:判断问题的原因
第三步:暴力拆卸
这个修理的步骤就是面向过程,所谓的面向过程就是:强调的是步骤、过程、每一步都是自己亲自去实现的。
如果采用面向对象的思想,那么应该怎样修车呢?
找4s店的工作人员来帮我们修车,但是到底怎么修,我们是不用考虑的,也就是说我们不关心步骤与过程。
所谓的面向对象其实就是找一个专门做这个事的人来做,不用关心具体怎么实现的。
所以说,面向过程强调的是过程,步骤。而面向对象强调的是对象,也就是干事的人。
大家可以想一下,在生活中还有哪些事情是面向过程,面向对象的。
比如说,玩游戏,如果是面向过程,就是自己玩,自己打怪升级。如果是面向对象,可以找代练,一切打怪升级都有代练完成,不需要我们自己关心了。
比如说,做饭,面向过程就是自己做,自己买菜,自己洗,自己炒,整个过程都有自己来完成,但是如果是面向对象,可以叫外卖,不用关心饭是怎么做的。
所以通过以上案例,大家能够体会出,面向过程就是强调的步骤,过程,而面向对象强调的是对象,找个人来做。

在面向对象中,还有两个概念是比较重要的,一是对象,二是类。
什么是对象呢?
万物皆对象,例如张三同学是一个对象,李四同学也是一个对象
那么我们在生活中怎样描述一个对象呢?
比如,描述一下张三同学:
姓名:张三
性别:男
身高:180cm
体重:70kg
年龄:22岁
吃喝拉撒睡一切正常 健康
吃喝嫖赌抽

通过以上的描述,可以总结出在生活中描述对象,可以通过特征(身高,体重,年龄等)和行为(爱好等)来进行描述。
那么在程序中,可以通过属性和方法(函数)来描述对象。属性就是特征,方法(函数)就是行为。所以说,对象必须具有属性和方法。虽然说,万物皆对象,但是在描述一个对象的时候,一定要具体不能泛指,例如,不能说“电灯”是一个对象,而是说具体的哪一台“电灯”。
大家可以思考一下,如果我们现在描述一下教室中某一台电灯,应该有哪些属性(特征)和方法(行为)呢?

下面我们在思考一下,下面这道题:
张三(一个学生)\杨老师\邻居售货员张阿姨\李四的爸爸\李四的妈妈
找出这道题中所有对象的共性(所谓共性,指的是相同的属性和方法)。
所以说,我们可以将这些具有相同属性和相同方法的对象进行进一步的封装,抽象出来类这个概念。
类就是个模子,确定了对象应该具有的属性和方法。
对象是根据类创建出来的
例如:上面的案例中,我们可以抽出一个“人”类(都有年龄,性别,姓名等属性,都有吃饭,走路等行为),“张三”这个对象就是根据“人”类创建出来的,也就是说先有类后有对象。
1:GO语言中的面向对象
前面我们了解了一下,什么是面向对象,以及类和对象的概念。但是,GO语言中的面向对象在某些概念上和其它的编程语言还是有差别的。
严格意义上说,GO语言中没有类(class)的概念,但是我们可以将结构体比作为类,因为在结构体中可以添加属性(成员),方法(函数)。
面向对象编程的好处比较多,我们先来说一下“继承”,

所谓继承指的是,我们可能会在一些类(结构体)中,写一些重复的成员,我们可以将这些重复的成员,
单独的封装到一个类(结构体)中,作为这些类的父类(结构体),我们可以通过如下图来理解:
1.png
当然严格意义上,GO语言中是没有继承的,但是我们可以通过”匿名组合”来实现继承的效果。

01匿名字段实现继承

  1. package main
  2. import "fmt"
  3. type Person struct {
  4. id int
  5. name string
  6. age int
  7. sex string
  8. }
  9. type Student struct {
  10. //将Person结构体作为student结构体的成员
  11. Person //匿名字段实现继承关系
  12. //p Person //为Person结构体起名字
  13. class string
  14. score int
  15. }
  16. func main1() {
  17. var stu Student
  18. //student继承与父类person可以直接使用父类的结构体成员
  19. stu.Person.name = "xxd"
  20. stu.Person.age = 19
  21. stu.Person.id = 101
  22. stu.sex = "男"
  23. stu.class = "3年级1班"
  24. stu.score = 100
  25. fmt.Println(stu) //{{101 xxd 19 男} 3年级1班 100}
  26. }
  27. func main() {
  28. str := Student{Person{01, "一方", 18, "男"}, "2年级1班", 99}
  29. fmt.Printf("ID:%d\n", str.id) //ID:1
  30. fmt.Printf("姓名:%s\n", str.name) //姓名:一方
  31. fmt.Printf("年龄:%d\n", str.age) //年龄:18
  32. fmt.Printf("性别:%s\n", str.sex) //性别:男
  33. fmt.Printf("班级:%s\n", str.class) //班级:2年级1班
  34. fmt.Printf("成绩:%d\n", str.score) //成绩:99
  35. }

02 匿名字段同名成员

package main

import "fmt"

type person struct {
    id   int
    name string
    age  int
    sex  string
}
type student struct {
    person
    name  string
    class int
    score int
}

func main() {
    //对象初始化
    //var stu student
    //stu.id = 1
    //stu.name = "李四"
    //stu.age = 18
    //stu.sex = "女"
    //stu.class = 301
    //stu.score = 99
    ////子类赋值
    ////子类和父类结构有相同的成员名,默认赋值为子类,采用就近原则
    ////父类赋值
    //stu.person.name = "xxd"
    stu := student{person{1, "李二", 18, "女"}, "李四", 301, 99}
    fmt.Println(stu)
}

03 匿名字段成员为指针

package main

import "fmt"

type person struct {
    id   int
    name string
    age  int
    sex  string
}

type student struct {
    *person //指针作为匿名函数
    class   int
    score   int
}

func main() {
    var stu student
    stu.class = 301
    stu.score = 99
    ////stu.person是一个指针类型 默认值为nil 0
    ////需要对指针进行创建空间 new(person)
    //stu.person = new(person)
    //stu.name = "李四"
    //stu.id = 1
    //stu.age = 18
    //stu.sex = "男"
    //fmt.Println(stu)
    stu.person = &person{1, "daong", 18, "男"}
    fmt.Printf("ID:%d\n", stu.id)    //ID:1
    fmt.Printf("姓名:%s\n", stu.name)  //姓名:一方
    fmt.Printf("年龄:%d\n", stu.age)   //年龄:18
    fmt.Printf("性别:%s\n", stu.sex)   //性别:男
    fmt.Printf("班级:%d\n", stu.class) //班级:2年级1班
    fmt.Printf("成绩:%d\n", stu.score) //成绩:99
}

04 多重继承

package main

import "fmt"

type person1 struct {
    name string
    age  int
    sex  string
}

type person2 struct {
    id   int
    addr string
}

type student struct {
    //结构体成员为多个匿名字段
    person1
    person2

    class int
    score int
}

func main() {
    //var stu student
    //stu.age = 18
    //stu.class = 301
    //stu.score = 99
    //stu.name = "托儿索"
    //stu.addr = "召唤师峡谷"
    //stu.id = 1
    //stu.sex = "男"
    stu := student{person1{"dd", 18, "男"}, person2{1, "召唤师峡谷"}, 301, 99}
    fmt.Println(stu) //{{托儿索 18 男} {1 召唤师峡谷} 301 99}
}

05 多重继承-2

package main

import "fmt"

type person1 struct {
    name string
    age  int
    sex  string
}

type person2 struct {
    person1
    id   int
    addr string
}

type student struct {
    //结构体成员为多个匿名字段
    person2
    class int
    score int
}

func main() {
    //var stu student
    //stu.age = 18
    //stu.class = 301
    //stu.score = 99
    //stu.name = "托儿索"
    //stu.addr = "召唤师峡谷"
    //stu.id = 1
    //stu.sex = "男"
    stu := student{person2{person1{"托儿索", 18, "男"}, 1, "召唤师峡谷"}, 301, 99}
    fmt.Println(stu) //{{{托儿索 18 男} 1 召唤师峡谷} 301 99}
}

06 对象的创建和使用-1

package main

import "fmt"


//1、定义函数类型  定义结构体名称
//2、为已存在的数据类型起别名
type Int int

//对象的方法

//func (对象)方法(参数列表)(返回值列表){
//    代码体
//}

func (a Int) add(b Int) Int {

    fmt.Println(a)
    fmt.Println(b)
    return a + b
}
func main() {

    //将源文件编译成可执行程序
    //编译过程
    //1、预处理 包展开 替换数据类型  去掉注释
    //2、编译  如果代码有错会提示 如果没错会编译成汇编文件
    //3、汇编  将汇编文件转成二进制文件
    //4、链接  将支持的库链接到程序中 变成可执行程序

    //类型别名会在编译时进行转换
    var a Int = 10

    var b Int =20
    //var b Int = 20
    //包.函数 结构体.成员 对象.方法
    //sum:=a.add(b)

    //对象.方法
    //想要使用方法 必须是相同类型的对象才可以
    sum:=b.add(a)
    fmt.Println(sum)
    //var b int = 20

    //fmt.Println(a + 10)

    //fmt.Printf("%T\n", a)

}

07 对象方法的创建和使用-2

package main

import "fmt"

type student5 struct {
    name  string
    age   int
    sex   string
    score int
    addr  string
}

//函数
func Print() {
    fmt.Println("hello world")
}

//结构体类型可以作为对象类型
func (s student5) Print() {
    fmt.Printf("%p\n",&s)

    fmt.Printf("姓名:%s\n", s.name)
    fmt.Printf("年龄:%d\n", s.age)
    fmt.Printf("性别:%s\n", s.sex)
    fmt.Printf("成绩:%d\n", s.score)
    fmt.Printf("地址:%s\n", s.addr)
}

func main() {

    //创建对象
    stu := student5{"贾政", 58, "男", 80, "贾府"}
    fmt.Printf("%p\n",&stu)
    //对象.方法
    stu .Print()
    fmt.Println(stu)

    stu1 := student5{"贾玲", 29, "女", 99, "北京"}
    stu1.Print()

    //打印错误日志使用函数
    //print()
    //函数调用
    //Print()

    //对象的方法名可以和函数名重名  但是相同的对象方法名不能重名
    //fmt.Println(stu.Print)
    //fmt.Println(stu1.Print)
    //打印函数在代码区的地址
    fmt.Println(Print)
}

08方法的内存模型

package main

import "fmt"

type student6 struct {
    name  string
    age   int
    sex   string
    score int
    addr  string
}

//对象不同方法名相同 不会冲突
//在方法调用中 方法的接收者为指针类型
//指针类型 和普通类型表示是相同对象的类型

func (s *student6) Print() {
    s.name = "黄月英"
    s.score = 99
    //fmt.Println(*s)

}
func main() {
    stu := student6{"貂蝉", 22, "女", 80, "徐州"}

    //地址传递(*student6) 值传递(student6)
    //一般建议选择地址传递
    stu.Print()

    fmt.Println(stu)
}

09 方法继承

package main

import "fmt"

type person7 struct{
    id int
    name string
    age int
    sex string
}

type student7 struct {
    person7

    class int
    score int
    addr string
}

func (p *person7)Print(){
    fmt.Printf("编号:%d\n",p.id)
    fmt.Printf("姓名:%s\n",p.name)
    fmt.Printf("年龄:%d\n",p.age)
    fmt.Printf("性别:%s\n",p.sex)

}


func main() {

    p:=person7{1001,"孙尚香",32,"女"}
    p.Print()

    s:=student7{person7{1002,"糜夫人",32,"女"},302,100,"巴蜀"}

    //子类继承于父类  可以继承结构体的成员(属性)  也可以继承父类的方法
    //父类不能继承于子类
    s.Print()

}

10 方法练习

package main

import (
    "fmt"
)

/*
记者:我是记者  我的爱好是偷拍 我的年龄是34 我是一个男狗仔
程序员:我叫孙权 我的年龄是23 我是男生 我的工作年限是 3年
 */

//父类
type Human struct {
    name string
    age  int
    sex  string
}

//记者子类
type Reper struct {
    Human

    hobby string
}

//程序员子类
type Dever struct {
    Human

    worktime int
}

//父类方法
func (h *Human) SayHi() {
    fmt.Printf("大家好,我叫%s,我今年%d岁,我是%s生", h.name, h.age, h.sex)
}

//记者的方法
func (r *Reper) SayHello() {
    //继承父类方法
    r.SayHi()
    fmt.Printf(",我的爱好是:%s\n", r.hobby)

}

//程序员的方法
func (d *Dever) SayHello() {
    d.SayHi()
    fmt.Printf(",我的工作年限是:%d年\n", d.worktime)
}
func main() {

    r:=Reper{Human{"卓伟",40,"男"},"偷拍"}
    r.SayHello()

    d:=Dever{Human{"图灵",32,"男"},10}
    d.SayHello()

}

11 方法重写