Golang-面向对象

195 阅读3分钟

结构体和方法

在Go语言中,没有和java一样的class,只有结构体。和其他语言相比,Go语言放弃了大量面向对象的特性。

结构体

定义

type 结构体名 struct {
    属性名   属性类型
    属性名   属性类型
    ...
}
type Leg struct {
  length int
}

type Hand struct {
  length int
}

type Face struct {
  name string
}

type Other struct {
  name string
}

type Person struct {
  name, gender string
  age          int
  legs         []Leg
  hands        []Hand
  face         Face
  other        *Other
}

实例化方法

正常的实例化

person := Person{
   name:   "姓名",
   age:    18,
   gender: "male",
}

使用new

person := new(Person)
person.name = "name"

使用&

person := &Person{}

来个复杂点的例子,像写json一般:

func TestStruct() {

  person := Person{
    name:   "姓名",
    age:    18,
    gender: "male",
    legs: []Leg{
      {
        length: 10,
      },
      {
        length: 10,
      },
    },
    hands: []Hand{
      {
        length: 5,
      },
      {
        length: 5,
      },
    },
    face: Face{
      name: "face",
    },
    other: &Other{
      name: "other",
    },
  }
  fmt.Printf("person: %v\n", person)
}

输出:

person: {姓名 male 18 [{10} {10}] [{5} {5}] {face} 0xc00004e230}

结构体的方法-组合函数

在 Go 语言中,我们无法像其他语言的class一般,在结构体(类)内定义方法,Go使用组合函数的方式来为结构体定义结构体方法。

func (person Person) say() {
  fmt.Printf("my name is: %v\n", person.name)
}

say是方法名,(person Person)表示将say方法与Person绑定。

方法的参数传递

func (Person Person) rename() {
  Person.name = "新名字"
}

结果:

person.say() // my name is: 姓名
person.rename()
person.say() // my name is: 姓名

上面那个简单例子,无法在方法里面改变实例person的属性,因为他是值拷贝。所以这里需要用到指针。

func (Person *Person) rename() {
  Person.name = "新名字"
}

结果:

person.say() // my name is: 姓名
person.rename()
person.say() // my name is: 新名字

内部方法和外部方法

在 Go 语言中,函数名的首字母大小写非常重要,它被来实现控制对方法的访问权限。

  • 当方法的首字母为大写时,这个方法对于所有包都是Public,其他包可以随意调用
  • 当方法的首字母为小写时,这个方法是Private,其他包是无法访问的。

Go里的“继承”-组合

用组合实现继承

Go本身不支持继承,但我们可以通过组合去实现类似继承的效果,如下:

type Worker struct {
  workType string
  Person
}

Person是上面定义的struct,这里的Person会作为一个匿名变量。

我们可以直接调用say(),也可以调用Person.say()

  worker1 := Worker{workType: "coder", Person: person}
  worker1.say() // my name is: 姓名
  worker1.Person.say() // my name is: 姓名

实现方法重载

func (person Person) say() {
  fmt.Printf("my name is: %v\n", person.name)
}

func (worker *Worker) say() {
  worker.Person.say()
  fmt.Printf("worker name is: %v\n", worker.name)
}

执行worker1.say(),结果为:

my name is: 姓名
worker name is: 姓名

接口和多态

定义接口

使用type关键字来定义接口

type Product interface {
  calculatePrice() int
  getQuantity() int
}

实现接口

如果有一个类型/结构体A,实现了一个接口B的所有方法, 那么我们就可以称A实现了B接口。

type Product interface {
  calculatePrice() int
  getQuantity() int
}

type Keyboard struct {
  name     string
  quantity int
  price    int
}

func (keyboard *Keyboard) calculatePrice() int {
  payment := keyboard.price * keyboard.quantity

  fmt.Printf("payment: %v\n", payment)
  return payment
}

func (keyboard *Keyboard) getQuantity() int {
  fmt.Printf("keyboard.quantity: %v\n", keyboard.quantity)
  return keyboard.quantity
}

实现多态

package interfacetest

import "fmt"

func Execute() {
  products := []Product{}
  products = append(products, &Keyboard{name: "keyboard", quantity: 2, price: 10})
  products = append(products, &Mouse{name: "mouse", quantity: 3, price: 20})

  for _, p := range products {
    p.getQuantity()
    p.calculatePrice()
  }
}

type Product interface {
  calculatePrice() int
  getQuantity() int
}

type Keyboard struct {
  name     string
  quantity int
  price    int
}

func (keyboard *Keyboard) calculatePrice() int {
  payment := keyboard.price * keyboard.quantity

  fmt.Printf("%v payment: %v\n", keyboard.name, payment)
  return payment
}

func (keyboard *Keyboard) getQuantity() int {
  fmt.Printf("keyboard.quantity: %v\n", keyboard.quantity)
  return keyboard.quantity
}

type Mouse struct {
  name     string
  quantity int
  price    int
}

func (mouse *Mouse) calculatePrice() int {
  payment := mouse.price * mouse.quantity

  fmt.Printf("%v payment: %v\n", mouse.name, payment)
  return payment
}

func (mouse *Mouse) getQuantity() int {
  fmt.Printf("mouse.quantity: %v\n", mouse.quantity)
  return mouse.quantity
}

运行结果:

keyboard.quantity: 2
keyboard payment: 20
mouse.quantity: 3
mouse payment: 60

完整的代码实例可参考: gitee代码仓库