📕
innohub
  • KEEP LEARNING
  • WebInfo
    • JS 部分运算符操作
    • javascript 中的object array
    • 错误处理以及异常捕获
    • JavaScript Bases
    • LaoZi & Confucius
  • PyInfo
    • Python3 输入与输出
    • Python3OS
    • python 修饰器的使用
    • python3 与mysql数据库连接使用实例
    • Format-specifier
    • CGI初学踩坑
    • Django 项目测试
    • Assert-info
    • 使用ngnix和uWSGI配置Django
    • write|SVN​
    • Matplotlib 基本使用
    • 重读 Python 官方文档
    • Python3 Base
    • python3 多线程
    • Python3 函数解析
    • python3 str 对象的基本操作
    • protocl buffers
    • Iterator-Generator
    • Django base
    • Decorator 2
    • Export to wheel or egg-info
    • 三. 运算、数据及逻辑
  • GoInfo
    • Info
      • Select 语句使用
      • First class function
      • Work Pools
      • StructTag
      • Go struct
      • 常用函数
      • Strings操作
      • Golang Bases
      • 数组以及切片
      • 文件操作
      • Golang 中的指针类型
      • Golang Map 类型
      • Reflection
      • 函数闭包
      • 接口
      • Panic and Recover
      • Go中的错误处理
      • 并发
      • defer usage
      • Method in golang
      • Object-oriented Programming
      • Goalng 包管理机制
  • RustInfo
    • Info
      • 包、crate、模块
      • Rust 中的错误处理
      • 智能指针
      • 泛型 generics
      • 数据布局与内存对齐
      • Functions and methods
      • 无畏并发
      • Actix-web 基本使用
      • Got from guessing game
      • 结构体的使用
      • Rust 中的函数式语言功能
      • 集合类型
      • 枚举以及模式匹配
      • Slice 类型
      • 生命周期
      • 测试
      • Rust 中的所有权
      • trait
      • 不安全 Rust
      • Format_print
      • Rust 通用编程概念
      • Macro
  • OS
    • info
      • 内存屏障 -- Part 1
      • 内存屏障 -- Part 2
      • CPU 上下文切换
      • 文件读写与零拷贝
      • ELF 文件
  • MySql
    • info
      • MySql 架构与历史
      • 02-key
  • kubernetes
    • 第二章 k8s 基本概念
    • 第一章 Kubernetes -- 伟大舵手
  • Redis
    • info
      • Redis 总览
      • 02-underline-ds
  • Shell&CInfo
    • GCC 与make的使用
    • C++ 中 malloc 与 new
    • 位运算符操作
    • Base of C macro
    • C 语言中 extern 关键字的用法
  • Distributed
    • info
      • 分布式理论概述
  • Java
    • info
      • Java 内存模型
  • Prometheus
    • Prometheus -- 不灭之火
Powered by GitBook
On this page
  • 1. Go不是纯面向对象的语言
  • 2. 使用组合代替继承
  • 2.1 结构体的嵌套
  • 2.2 嵌套的切片类型
  • 2.3 在其他包使用
  • 3. 多态 Polymorphism

Was this helpful?

  1. GoInfo
  2. Info

Object-oriented Programming

PreviousMethod in golangNextGoalng 包管理机制

Last updated 5 years ago

Was this helpful?

[TOC]

1. Go不是纯面向对象的语言

Golang不是一个纯面向对象的语言,摘自Golang [FAQ](This excerpt taken from Go's answers the question of whether Go is Object Oriented.) ,解释了golang是否为面向对象的语言。

Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of “interface” in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).

也就是说使用类型以及menthods可以实现面向对象编程的类似功能,但是不存在类型的继承。使用了interface实现了不一样的解决方案,更加易用而且更加通用。

可以使用struct代替类,如果需要使用可见性约束的类,可以定义包内类型,然后定义exported methods ,定义New() T作为构造器的模拟,同时使用其他方法,使得接收器为该类型变量:

// Define the struct with all fields exported
type employee struct {
  firstName, lastName string
  totalLeaves, leavesTaken int
}

// Exported method with a receiver of Employee
func (e employee) LeavesRemaining() {
  fmt.Printf("%s %s has %d leaves remaining.\n",
              e.firstName, e.lastName, (e.totalLeaves - e.leavesTaken))
}

// New function as a Constructor
func New(firstName, lastName string, totalLeaves, leavesTaken int)  employee {
  e := employee {firstName, lastName, totalLeaves, leavesTaken}
  return e
}

// Property of employee
func (e employee) GetFirstName() string {
  return e.firstName
}

func (e employee) GetLastName() string {
  return e.lastName
}

func (e employee) GetTotal() int {
  return e.totalLeaves
}

2. 使用组合代替继承

Golang不支持继承机制,但是支持组合composition。组合的一般定义是能将多个部分放在一起。在Golang中使用接阔的嵌套实现组合机制,

2.1 结构体的嵌套

在一个结构体中使用另一个结构体作为其域可以实现组合的机制,同时借助匿名域可以直接使用外部类型调用内部类型的方法。使用匿名域时只需要指明类型即可,不需要给一个域命名,但是匿名域每一个类型只可以有一个。

// author of the post
type author struct {
  firstName, lastName string
  bio string
}

// get the author full name
func (a author) AuthorName() string {
  return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

// struct of post, `author` field promoted
// so Post type can use `AuthorName` directly
type Post struct {
  Title string
  Content string
  author
}

func (p Post) Detail() {
  fmt.Println("Post:", p.Title)
  fmt.Println("Content:", p.Content)
  fmt.Println("Author:", p.AuthorName())
  fmt.Println("Bio", p.bio)
}

2.2 嵌套的切片类型

可以在一个结构体内部定义另一个结构体的切片作为该结构体的域,但是注意如果需要访问该切片field,就不可以将其定义为匿名域

type website struct {  
        []post
}
func (w website) contents() {  
    fmt.Println("Contents of Website\n")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

编译器会报错:

syntax error: unexpected [, expecting field name or embedded type

2.3 在其他包使用

如果一个含有unexported field的struct需要在包外使用,需要在包外初始化该对象,那么可以通过package.NewT(), 方法来作为该对象的一个构造器。即使内部嵌套类型有一个无法导出的域,也需要使用该方式。

// post/website.go
package post

import "fmt"

// define the websites struct which contains posts
type WebSite struct {
  Posts []Post
}

// display the website msssage
func (w WebSite) Display() {
  fmt.Println("The content of the website:\n")
  for _, po := range w.Posts {
    po.Detail()
    fmt.Println()
  }
}
// post/post.go
package post

/* define the post struct */
import (
  "fmt"
)

// author of the post
type author struct {
  firstName, lastName string
  bio string
}

// get the author full name
func (a author) AuthorName() string {
  return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}

func Newauthor(firstName, lastName, bio string) author {
  return author{firstName, lastName, bio}
}

// struct of post, `author` field promoted
// so Post type can use `AuthorName` directly
type Post struct {
  Title string
  Content string
  author
}

func NewPost(title, content string, a author) Post {
  return Post{title, content, a}
}

func (p Post) Detail() {
  fmt.Println("Post:", p.Title)
  fmt.Println("Content:", p.Content)
  fmt.Println("Author:", p.AuthorName())
  fmt.Println("Bio:", p.bio)
}

3. 多态 Polymorphism

在golang中使用接口来实现多态。通过定义同一类型的接口,接口可以被隐式的实现。需要使用这个接口中的类型可以实现接口中的所有方法,然后使用接口变量指向这些类型变量。实现多态操作。使用接口的最大好处在于提高了代码的可复用性,如果有新的类型需要加入到代码中,不需要更改其他部分,只需要添加该类型以及接口的实现。

一个接口类型的变量,可以指向任何一个实现了该接口的值。使用该特性来实现多态。

package main

import (  
    "fmt"
)

type Income interface {  
    calculate() int
    source() string
}

type FixedBilling struct {  
    projectName string
    biddedAmount int
}

type TimeAndMaterial struct {  
    projectName string
    noOfHours  int
    hourlyRate int
}

func (fb FixedBilling) calculate() int {  
    return fb.biddedAmount
}

func (fb FixedBilling) source() string {  
    return fb.projectName
}

func (tm TimeAndMaterial) calculate() int {  
    return tm.noOfHours * tm.hourlyRate
}

func (tm TimeAndMaterial) source() string {  
    return tm.projectName
}

func calculateNetIncome(ic []Income) {  
    var netincome int = 0
    for _, income := range ic {
        fmt.Printf("Income From %s = $%d\n", income.source(), income.calculate())
        netincome += income.calculate()
    }
    fmt.Printf("Net income of organisation = $%d", netincome)
}

func main() {  
    project1 := FixedBilling{projectName: "Project 1", biddedAmount: 5000}
    project2 := FixedBilling{projectName: "Project 2", biddedAmount: 10000}
    project3 := TimeAndMaterial{projectName: "Project 3", noOfHours: 160, hourlyRate: 25}
    incomeStreams := []Income{project1, project2, project3}
    calculateNetIncome(incomeStreams)
}

注意使用接口时,如果是指针类型实现了接口的方法,那么指针类型才可以赋值给该接口类型。不存在指针的隐式转换。只有在方法中存在指针的隐式转换。

FAQs