sunwenfei
  • 关于我
  • Golang
    • Goglang基础教程【译】
      • 介绍
        • 安装
        • Hello World
      • 变量、基本类型以及常量
        • 变量
        • 基本类型
        • 常量
      • 函数和包
        • 函数
        • 包
      • 条件、循环流程控制语句
        • if else条件语句
        • switch语句
        • 循环语句
      • 数组、切片、变参函数
        • 数组(Array)
        • 切片(Slice)
        • 变参函数
      • 其他数据类型
        • 映射(Map)
        • 字符串
      • 指针、结构体和方法
        • 指针
        • 结构体
        • 方法
      • 面向对象编程
        • 结构体 vs 类
        • 组合 vs 继承
        • 接口
        • 多态
      • 并发
        • 并发介绍
        • 协程(goroutine)
        • 管道(channel)
        • 带缓存的管道(buffered channel)
        • 协程池
        • 管道选择器(select)
        • 互斥锁(Mutex)
      • Defer
      • 一等公民函数
      • 反射
      • 错误
        • 错误处理
        • 自定义错误类型
        • panic和recover
      • 文件读写
        • 读文件
        • 写文件
    • Golang面向对象编程
    • Golang函数式编程
    • Golang并发编程
    • Golang web服务编程
    • Golang数据结构与算法
  • Shell编程
    • Find命令
  • JavaScript
    • browser
    • Node.JS
    • Deno
  • TypeScript
  • HTTP
    • 【译】通过信鸽理解HTTPS交互原理
  • React
    • React16
      • Hooks
        • 使用React Hooks拉取数据
  • 移动端开发
    • 原生
    • Flutter
    • ReactNative
    • 小程序
  • 前端测试
Powered by GitBook
On this page

Was this helpful?

  1. Golang
  2. Goglang基础教程【译】
  3. 面向对象编程

组合 vs 继承

Golang不支持继承,但支持组合。怎么理解组合呢?可以拿车来举例,车就是一个轮子、发动机等组件的一个组合。这个模式跟现在流行的前端开发模式有点像,比如React组件化,也是推崇组合,摒弃继承。

实现组合:结构体嵌套

Golang中可以通过结构体嵌套来实现组合。我们拿博客来举个例子,一篇博客包含标题、内容以及作者等信息,这三部分组合在一起形成一篇博客。 我们首先创建一个结构体类型author用来表示作者。

package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

这里我们首先创建了一个结构体类型author,该结构体类型包含三个属性firstName、lastName以及bio。然后我们给该结构体类型绑定了一个方法fullName用来获取姓名全称。

下面我们来创建博客结构体类型post,并绑定一个方法details。

type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.author.fullName())
    fmt.Println("Bio: ", p.author.bio)
}

这里的结构体类型post包含title、content两个属性,还包含一个匿名嵌套属性author。这里包含了一个嵌套结构体author,因此我们说author是post的一个组成部分,或者说post由author组成。这时我们可以通过post来访问author的各个属性和方法。 在details方法中我们通过结构体类型post来访问了title、content属性字段以及author属性的fullName方法和bio属性。

对于匿名嵌套属性,我们可以简写如下,将匿名字段略去:

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

到这里我们已经定义好了两个结构体类型及其绑定的方法:author和post,下面写个测试程序来测试下:

package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

func main() {
    author1 := author{
        "Naveen",
        "Ramanathan",
        "Golang Enthusiast",
    }

    post1 := post{
        "Inheritance in Go",
        "Go supports composition instead of inheritance",
        author1,
    }

    post1.details()
}

该程序输出如下:

Title:  Inheritance in Go
Content:  Go supports composition instead of inheritance
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast

嵌套结构体切片

前面我们看到,一个post可以由title、content和author组成,这三个属性都是单个的。但是一个网站(website)肯定是包含多条博客(post)的,因此我们可以在website结构体类型下面掐套一个post结构体切片:

type website struct {
    posts []post
}

func (w website) contents() {
    fmt.Println("Contents of website")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

这里我们在结构体website内部嵌套的是切片类型[]post。我们再升级下main函数来创建多个post结构体变量,并创建一个website结构体变量:

package main

import "fmt"

type author struct {
    firstName string
    lastName  string
    bio       string
}

func (a author) fullName() string {
    return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

type post struct {
    title   string
    content string
    author
}

func (p post) details() {
    fmt.Println("Title: ", p.title)
    fmt.Println("Content: ", p.content)
    fmt.Println("Author: ", p.fullName())
    fmt.Println("Bio: ", p.bio)
}

type website struct {
    posts []post
}

func (w website) contents() {
    fmt.Println("Contents of website")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

func main() {
    author1 := author{
        "Naveen",
        "Ramanathan",
        "Golang Enthusiast",
    }
    post1 := post{
        "Inheritance in Go",
        "Go supports composition instead of inheritance",
        author1,
    }
    post2 := post{
        "Struct instead of Classes in Go",
        "Go does not support classes but methods can be added to structs",
        author1,
    }
    post3 := post{
        "Concurrency",
        "Go is a concurrent language and not a parallel one",
        author1,
    }

    w := website{
        posts: []post{post1, post2, post3},
    }
    w.contents()
}

这里我们创建了三个结构体post类型的变量post1,post2,post3,然后构建了一个切片内嵌到了结构体变量w内。

该程序输出如下:

Contents of website
Title:  Inheritance in Go
Content:  Go supports composition instead of inheritance
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast

Title:  Struct instead of Classes in Go
Content:  Go does not support classes but methods can be added to structs
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast

Title:  Concurrency
Content:  Go is a concurrent language and not a parallel one
Author:  Naveen Ramanathan
Bio:  Golang Enthusiast
Previous结构体 vs 类Next接口

Last updated 5 years ago

Was this helpful?