Golang 面向对象编程

简介: Golang 面向对象编程

Golang 是面向对象的么?

是,也不是。尽管 Go 有类型和方法,并且允许面向对象风格的编程,但没有类型层次结构。Go 的『接口』概念提供了一种不同的实现方式,在某些方面更通用。同时,缺少类型层次结构使 Go 的『对象』感觉上比 C++ 或 Java 等语言中的『对象』轻很多。本文的目的就是通过示例来说明,如何使用 Golang 进行面向对象编程

过程化

以下是一个关于身份证ID的示例,用于从身份证中提取生日。通常的实现版本如下:

func Birthday(id string) string {
  return id[6:14]
}
const (
  id = "412717199109031697"
)
func Test_Birthday(t *testing.T) {
  found := Birthday(id)
  wanted := "19910903"
  if found != wanted {
    t.Errorf("unexpected birthday, wanted:%v, found:%v", wanted, found)
  }
}

简单的数据,如此实现倒也问题不大。但生产环境中往往遇到的都是复杂的多的数据和操作。此时就需要将数据和操作封装在一起

封装

Golang 中可以通过 type 关键字创建新的类型,同时使用 NewXXX 的风格创建对象。

type ID string
func NewID(id string) (ID, error) {
  if len(id) != 18 {
    return "", errors.New(fmt.Sprintf("error id length:%v", len(id)))
  }
  return ID(id), nil
}
func (i ID) Birthday() string {
  return string(i[6:14])
}
func TestID_Birthday(t *testing.T) {
  found := ID(id).Birthday()
  wanted := "19910903"
  if found != wanted {
    t.Errorf("unexpected birthday, wanted:%v, found:%v", wanted, found)
  }
}

当业务变得更加复杂,同一种功能,存在多种实现方式,比如支付方式,微信支付、京东支付、支付宝、银联等不同渠道的大概流程大抵相似,但实现细节有所区别。此时就需要借助多态的动态绑定来进行业务抽象。

多态

Golang 中动态绑定方法的唯一方式是通过接口(interface)来实现的。结构或其他具体类型上的方法始终是静态的。

type ID interface {
  Birthday() string
}
type id string
func NewID(i string) (ID, error) {
  if len(i) != 18 {
    return nil, errors.New(fmt.Sprintf("error id length:%v", len(i)))
  }
  return id(i), nil
}
func (i id) Birthday() string {
  return string(i[6:14])
}
const (
  fakeid = "412717199109031697"
)
func TestID_Birthday(t *testing.T) {
  var i ID
  i, _ = NewID(fakeid)
  found := i.Birthday()
  wanted := "19910903"
  if found != wanted {
    t.Errorf("unexpected birthday, wanted:%v, found:%v", wanted, found)
  }
}

除了线性的业务逻辑处理场景,在生产中还会遇到层状的业务流,但是不同层次之间又有很多功能是相通的,此时就需要借助“继承”之类的能力,来实现代码复用。遗憾的是 Golang 中并不存在继承,下面我们介绍它的替代者

组合

在最知名的语言中,面向对象编程很多讨论是关于类型之间关系的。Go 采用了不同的实现 —— 隐藏类式的类型依赖。

在 Go 中,类型会自动满足指定其方法子集的任何接口,无需提前声明两种类型相关联。类型可以一次满足许多接口,而没有传统的多重继承的复杂性。 类型和接口之间没有明确的关系,所以不涉及类型层次结构。类似想法可以用来构造像类型安全的 Unix 管道一样的实现。

所有的“继承”之类的实现,在 Golang 中都能以组合(或内嵌)的方式来实现,组合和内嵌的对象可以是具体的类型,也可以抽象的接口。以下示例介绍了两种风格的实现:

type Man interface {
  Birthday() string
}
func NewMan(name, id string) (Man, error) {
  i, err := NewID(id)
  return &man{
    id:   i,
    name: name,
  }, err
}
func NewManEmbedding(name, id string) (Man, error) {
  i, err := NewID(id)
  return &manEmbedding{
    ID:   i,
    name: name,
  }, err
}
type man struct {
  id   ID
  name string
}
func (m *man) Birthday() string {
  return m.id.Birthday()
}
type manEmbedding struct {
  ID
  name string
}
const (
  peterid = "412717199109031697"
  samid   = "312717199109036148"
)
func TestMan_Birthday(t *testing.T) {
  peter, _ := NewMan("peter", peterid)
  sam, _ := NewMan("sam", samid)
  mans := []Man{peter, sam}
  for _, man := range mans {
    found := man.Birthday()
    wanted := "19910903"
    if found != wanted {
      t.Errorf("unexpected birthday, wanted:%v, found:%v", wanted, found)
    }
  }
}

总结

Write go in go way. Golang 很多经典的思想都可以通过官方文档获得,例如:FAQ

源代码:https://github.com/cyningsun/go-test/tree/master/20210311-oop-in-go

本文作者 : cyningsun

本文地址https://www.cyningsun.com/03-12-2021/oop-in-go.html

版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

# Golang

  1. 译|There Are No Reference Types in Go
  2. Go 语言没有引用类型,指针也与众不同
  3. 译|What “accept interfaces, return structs” means in Go
  4. 如何用好 Go interface
  5. 一个优雅的 LRU 缓存实现
目录
相关文章
|
5月前
|
安全 Java 编译器
第十一章 Golang面向对象编程(下)
第十一章 Golang面向对象编程(下)
56 2
|
12月前
|
安全 Go
Golang 语言是面向对象编程风格的编程语言吗?
Golang 语言是面向对象编程风格的编程语言吗?
43 0
|
28天前
|
Go
Golang语言结构体(struct)面向对象编程进阶篇(封装,继承和多态)
这篇文章是关于Go语言中结构体(struct)面向对象编程进阶篇的教程,涵盖了Go语言如何实现封装、继承和多态,以及结构体内存布局的相关概念和案例。
57 4
|
28天前
|
Go
Golang语言结构体(struct)面向对象编程基础篇
这篇文章是关于Go语言中结构体(struct)面向对象编程的基础教程,详细介绍了面向对象编程在Go语言中的应用、结构体的定义与初始化、方法定义、跨包实例化结构体以及结构体方法和普通函数的区别。
24 4
|
5月前
|
Go 开发者
Golang深入浅出之-Go语言方法与接收者:面向对象编程初探
【4月更文挑战第22天】Go语言无类和继承,但通过方法与接收者实现OOP。方法是带有接收者的特殊函数,接收者决定方法可作用于哪些类型。值接收者不会改变原始值,指针接收者则会。每个类型有相关方法集,满足接口所有方法即实现该接口。理解并正确使用这些概念能避免常见问题,写出高效代码。Go的OOP机制虽不同于传统,但具有灵活性和实用性。
43 1
|
5月前
|
程序员 Go
第十章 Golang面向对象编程(上)
第十章 Golang面向对象编程(上)
53 2
Golang面向对象编程之构造函数【struct&new】
Golang面向对象编程之构造函数【struct&new】
Golang面向对象编程之继承&虚基类【组合&接口】
Golang面向对象编程之继承&虚基类【组合&接口】
|
28天前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
53 4
Golang语言之管道channel快速入门篇
|
28天前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
46 4
Golang语言文件操作快速入门篇