GoLange:面向对象

ShineLee / 2023-08-22 / 原文

学习自:Go教程130页

1、类定义

方式:结构体+方法

  • 结构体:定义有哪些数据
  • 方法:定义结构体的方法

例子:定义一个Person类

//结构体定义人的属性
type Person  struct {
    name string
    age int
}

//方法定义人的行为
func (p Person)Say(){
    fmt.Println( "my name is" ,p.name, " my age is" ,p.age)
}

2、创建对象

对象名 := 结构体名{变量1,变量2,...}

例子  

p1 := Person{"lnj",33}
p1.Say()
p2 := Person{"zs",18}
p2.say()

3、不同包中变量、函数、方法、类型的公私有问题

在Go中通过首字母大小写控制公私有:

  • 首字母小写——私有,仅在当前包中使用
  • 首字母大写——公有,其他包中也可以使用

例子

//公有:其他包也可用
//私有:仅当前包可以用
var num1 int = 123//私有
var Num1 int = 123//公有

type person struct{//结构体 私有
    name string
    age int
}

type Student struct{//公有
    Name string
    Age int
}

func test1(){//函数 私有
    ...
}
func Test2(){//公有
    ...
}

func (p person)say(){//方法 私有
    ...
}

func (s Student)Say(){//方法 公有
    ...
}

4、面向对象三大特性及实现:继承、封装、多态

1)封装

说明

对外界隐藏数据特性,只暴露对数据操作相关的方法

实现

  • 类-公有
  • 类数据-私有
  • 类方法-公有

例子

package model
type Person struct{ //类名大写 公有
    name string        //数据小写 私有
    age int
}
func (p *person)SetAge(age int){//方法大写 公有
        p.age=age;
}


//下文省略包名,Person和main分属不同包
func main(){
    //不能直接在创建对象时就赋初值了
    //错误写法
    p := model.Person("lnj".18)

    //正确1
    p := model.Person()
    p.SetAge(18)

    //正确2
    p := new(model.Person)
    p.SetAge(18)

  

2)继承

Go中继承是通过组合实现的

组合:

type Person struct{
    ...
}

type Student struct{
    Person//继承了Person的特性
    ...
} 

①普通继承

type Person struct{
    name string
    age int
}

type Student struct{
    Person //Student继承了Person的特性
    score int
}
type Teacher struct{
    Person //Teacher继承了Person的特性
    Title string
}

//具体应用
func main(){
    s := Student{Person{"lnj",18},99}
//输出继承的父类的属性,两种方法 s.Person.name s.name
}

  

继承过程中出现了重名,则采用就近原则

例子:Person和Student中都有name属性

type Person struct{
    name string
    age int
}
type Student struct{
    Person
    name string
    score int
}


func main(){
    s := Student{Person{"zs",18},"ls",99}

    s.name        //Student自己的name即ls
    s.Person.name//父类的name即zs

②多重继承

A→B→C

A→C←B

type Object struct{
    life int
}
type Person struct{
    Object
    name string
    age int
}
type Student struct{
    Person
    score int
}

初始化

s := Student{Person{Object{77},"zs",33},99}

访问

//对于Object中无重名属性life,三种访问方式均可
s.life
s.Person.life
s.Person.Object.life

//对于Person中无重名属性name age,有两种访问方式
s.age
s.Person.age

//对于Student独有属性score,只能通过它的对象访问
s.score

③方法继承

一般继承

type Person struct{
    ...
}
//父类方法
func {p Person)say(){
    ...
}

type Student struct{
    Person
    ...
}

func main(){
    stu := Student{...}
    stu.say()//直接调用继承来的方法
}

重写(子类和父类存在同名方法)

type Person struct{
    ...
}
//父类方法
func (p Person)say(){
    ...
}

type Student struct{
    Person
    ...
}
func (s Student)say(){
    ...
}


func main(){
    stu := Student{...}
    stu.say()//直接调用,调用的是自己的方法
    stu.Person.say()//对用父类方法
}

3)多态

多态:一个事物多种状态(一个事物既是它自己,又是它的父类)

Go中通过接口实现多态

//定义接口Animal
type Animal interface{
    Eat()
}

//定义两个具体的类Dog、Cat
type Dog struct{
    name string
    age int
}
type cat struct{
    name string
    age int
}

//实现接口方法
func(d Dog)Eat(){...}
func(c Cat)Eat(){...}

//实现类特有方法
func(c Cat)Special(){...}
func main(){
    //1、生成接口对象
    var a Animal;

    //2、灵活表现为不同的对象(需要是实现接口方法的类)
    a=Dog{"旺财",18}
    a.Eat()

    a=Cat{"喵喵",18}
    a.Eat()

    //3、调用对象特有方法
    //但是只有对象才能调用自己的方法,接口无法调用接口中没有的方法,所以这里要用ok-idiom,断言机制
    if cat,ok := a.(Cat);ok{
        cat.Special()
    }

}