Golang 面向对象编程思想

1.抽象

在定义一个结构体的时候,实际上就是把一类事物的共有的属性和行为提取出来,行成一个物理模型。这种研究问题的方法称为抽象。

面向对象编程的三大特性:

Golang仍然有面向对象编程的继承,封装和多态特性,只是实现的方式和其他OOP语言不一样,Golang的三大特性是如何实现?

  • 封装

  1)将结构体、字段(属性)的首字母小写(不能导出,其他包不能使用,类似private)

  2)给结构体所在包提供一个工厂模式的函数,首字母大写。类似一个构造函数

  3)提供一个首字母大写的Set方法(类似其他语言的public),用于对属性判断并赋值

    func(var 结构体类型名) SetXxx(参数列表) (返回值列表){

      //加入数据验证的业务逻辑

      var.字段= 参数

    }

  4)提供一个首字母大写的Get方法(类似其他语言的public),用于获取属性的值

    func(var 结构体类型名) GetXxx(){

      return var.字段

    }

  特别说明:在Golang开发中并没有特别强调封装,Golang本身对面向对象的特性做了简化。

 

2.封装

1)创建一个model的包,在包中创建一个person的结构体和相关方法,限制个别属性是否允许被其他包访问

package model

import "fmt"

//定义一个结构体
//Name 首字母大写,表示其他包可以直接访问
//age和sal 首字母小写,其他包是不能访问的
type person struct {
    Name string
    age  int
    sal  float64
}

//写一个工厂模式的函数,相当于构造函数
func NewPerson(name string) *person {
    return &person{
        Name: name,
    }
}

//为了访问age和sal我们编写一对SetXxx的方法和GetXxx的方法
func (p *person) SetAge(age int) {
    if age > 0 && age < 150 {
        p.age = age
    } else {
        fmt.Println("年龄范围不正确...")
    }
}

//获取年龄的Get方法
func (p *person) GetAge() int {
    return p.age
}

//SetSal方法
func (p *person) SetSal(sal float64) {
    if sal >= 3000 && sal <= 5000 {
        p.sal = sal
    } else {
        fmt.Println("薪水范围不正确...")
    }
}

//GetSal方法
func (p *person) GetSal() float64 {
    return p.sal
}

 

2)创建一个main的包,在包中创建一个main方法用于访问model中的结构体

package main

import (
    "fmt"
    "src/main/src/go_code/chapter04/demo10/model"
)

func main() {
    p := model.NewPerson("ckfuture")
    p.SetAge(18)
    p.SetSal(5000)
    fmt.Println(p)
    fmt.Println(p.Name, "age = ", p.GetAge(), " sal = ", p.GetSal())
}

运行如图:

代码结构:

 3.继承

 继承主要解决代码复用,让我们的编程更加靠近人类思维。

当多个结构体存在相同的属性(字段)和方法时,可以从这些结构体中抽象出结构体,在改结构体中定义这些相同的属性和方法。

其他的结构体不需要重新定义这些属性和方法,只需要嵌套一个匿名结构体即可。

也就是说:在Golang中,如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的字段和方法,从而实现了继承特性。

嵌套匿名结构体的基本语法:

type Goods struct{
    Name string
    Price int
}

type Book struct{
    Goods//这里就是嵌套匿名结构体Goods
    Writer string
}

 注意:结构体嵌入两个(或多个)匿名结构体,如两个匿名结构体有相同的字段和方法(同时结构体本身没有同名的字段和方法),在访问时,就必须名曲指定匿名结构体名字,否则编译报错。

    Name string
    Age int
}
type B struct{
    Name string 
    score int
}
type C struct{
    A
    B
}

多重继承

如果一个struct嵌套了多个匿名结构体,那么改结构体可以直接访问嵌套的匿名结构体的字段和方法,从而实现了多重继承。

1)如嵌入的匿名结构体有相同的字段名或者方法名,则在访问时,需要通过匿名结构体类型名来区别

2)为了保证代码的简洁性,建议不使用多重继承。

4.接口(interface)

基本介绍

  interface类型可以定义一组方法,但是这些不需要实现,并且interface不能包含任何变量,到某个自定义类型要使用的时候,在根据具体情况把这些方法写出来。

基本语法

type 接口名 interface{
    
    method1(参数列表) 返回值列表
    method2(参数列表) 返回值列表
}

实现接口所有方法

func(t 自定义类型) method1(参数列表) 返回值列表{

          //方法实现
}
func(t 自定义类型) method2(参数列表) 返回值列表{
          //方法实现
}

小结说明:

1)接口里的说有方法都没有方法体,即接口的方法都时没有实现的方法,接口体现了程序设计的多态和高内聚低耦合的思想。

2)Golang中的接口,不需要显式的实现,只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,Golang中没有implement这样的关键字。

    面向方法名实现接口

//声明一个接口
type Usb interface{
    Start()
    Stop()
}
type Phone struct{

}
//让Phone实现Usb的接口的方法
func (p Phone) Start(){
    fmt.Println("Phone is running~")
}
func (p Phone) Stop(){
    fmt.Println("Phone is Stoping~")
}

接口注意事项

1)接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量

2)接口中所有的方法都没有方法体,即都是没有实现的方法。

3)在Golang中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。

4)一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型。

5)只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。

6)一个自定义类型可以实现多个接口

7)Golang接口中不能有任何变量

8)一个接口(比如A接口)可以继承多个接口,这时如果要实现A接口,也必须将B,C接口的方法也全部实现。

posted @ 2021-06-08 07:56  创客未来  阅读(148)  评论(0编辑  收藏  举报