golang中的面向对象

392 阅读3分钟

背景

近些日子在看大话设计模式这本书,其中各类模式都有一个实例,书中源码用用C#写的。为了练习以及熟悉,笔者打算用golang写一版,刚写第一个简单工厂模式的代码就觉得不太对劲,感觉用golang的struct和interface实现各种类以及方法写的差强人意。golang是一门面向过程的语言,没有class这个关键字,但是oo思想在golang中是可以实现的,所以查找了一些资料进行整理。

官方说辞

Is Go an object-oriented language? 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).

Also, the lack of a type hierarchy makes “objects” in Go feel much more lightweight than in languages such as C++ or Java.

官方回答很有意思,yes and no,是也不是。golang有结构、方法以及接口,能允许面向对象编程的风格,但是它更轻、更通用,并且没有class这样一个显式概念。

面向对象

编程是一门技术,基于哲学,更是一门艺术,咱们不用拘泥于固有认知,只要能够实现面向对象的相关思想,那这门语言就是具备oo的能力。java之父在一次演讲中也坦言,再设计一次java,他绝不会让继承这么实现。

面向对象三大特性——

  • 封装
  • 继承
  • 多态

golang实现封装

golang通过struct和方法实现此特性

package Test

import "fmt"

/*
	创建时间:2020/10/21
	功能:实现oo封装特性
	作者:Andy_文铎
*/

type User struct {
	name string
	age  int
}

func (u User) GetName() string {
	return u.name
}

func (u User) GetAge() int {
	return u.age
}

func (u User) inUser() {
	fmt.Println("这是包内使用的函数,不对外接口!")
}

这里边一个struct实现了三个方法,但是其中首字母大写的两个方法是对外的,首字母小写的方法是不导出的、不对外。

golang实现继承

golang的继承是隐式继承,通过外部struct中嵌套匿名struct,外部struct可以直接使用匿名struct的属性

// +build ignore

package main

import "fmt"

/*
	创建时间:2020/10/21
	功能:实现oo继承特性
	作者:Andy_文铎
*/

type User struct {
	Name string
	Age  int
}

func (u User) GetName() string {
	return u.Name
}

func (u User) GetAge() int {
	return u.Age
}

func (u User) inUser() {
	fmt.Println("这是包内使用的函数,不对外接口!")
}

type App struct {
	User
	Belong string
	Size float64
}

// 这里App可以直接使用User的属性Name和Age
// 当然,也可以写成A.User.Name和A.User.Age
func (A App) ShowUserDetail() {
	fmt.Printf("UserName = %v \n UserAge = %v \n", A.User.Name, A.Age)
}

func main() {
	app := App{User{"andy", 18}, "Andy", 12.3}
	app.ShowUserDetail()
}

golang实现多态

这个就是通过golang的interface来实现

// +build ignore

package main

import "fmt"

/*
	创建时间:2020/10/21
	功能:实现oo多态特性
	作者:Andy_文铎
*/

type Ope interface {
	GetResult() int
}

type Add struct {
	NumA int
	NumB int
}

func (A Add) GetResult() int {
	result := A.NumA + A.NumB
	return result
}

type Sub struct {
	NumC int
	NumD int
}

func (S Sub) GetResult() int {
	result := S.NumC - S.NumD
	return result
}

type Facotory struct {
	Ope
}

func main() {
	// 创建Sub结构的Factory
	f := Facotory{Sub{3, 2}}
	// 调用的是Sub的方法
	result := f.GetResult()
	fmt.Printf("The result is %v \n", result)
}

结语

至此,golang相关的的面向对象的实现梳理完毕,从C++等面向对象语言的写法到golang的转换只能通过多写、多读来熟悉。总的而言,golang的哲学是越轻越好,只保留需要的。