Go面向对象 | Go主题月

1,211 阅读3分钟

我们都知道,go语言中是没有class的概念的,但是go语言还是支持面向对象编程,只不过go语言的面向对象有点异类。

什么是面向对象?

面向对象(OOP, Object-Oriented Programming),是一种编程思维方式和编码架构。

对象是一种对数据及其行为的抽象。

一个对象具有自己的状态(内部数据),行为(方法)和标识(内存中唯一的地址)。

虽然所有的对象都是唯一的,但是一些对象具有相同的特性和行为,因此这些对象可以被再次抽象,从而形成了的概念。

再往前一步,有一些类表现出了相似的行为(方法),将这些方法再次抽象从而形成接口,还有一种介于中间的类型抽象类

面向对象的核心是代码复用,然后然后衍生出一系列的概念与方法。

面向对象的特点

面向对象的三大基本特性,封装继承多态

封装,即对变量和方法的封装,并且赋予不同的访问权限。

继承,子类继承父类,通过合并特征和行为来创建新的类型。

多态,同样的形式,不同的行为。比如同样的接口不同的实现类;同样的方法名,不同的实现;同样的操作符,不同的计算方式等。

面向对象的一般形式

像典型的面向对象语言,比如Java, C++, JavaScript, Python等耳熟能详的语言,都会有这些功能或者是类似的功能。

类,抽象类,接口,继承,成员变量,成员函数,私有,公有,静态,泛型等。

Go中的面向对象

我更愿意将Go的面向对象称之为残缺的面向对象。因为Go的面向对象与一般意义上的面向对象有很大的差异。

首先Go中没有class这个关键词,但是却使用其他的方式来实现类似class的功能。

使用struct来作为成员变量

//person 结构体
type person struct {
	Name string // 共有
	age  int    // 私有
}

结构体变量的声明

// 使用new函数分配内存,返回指针
p1 := new(person)
p1.Name = "clz"
p1.age = 23

p2 := &person{"clz", 23}

注意,在Go的'类'中,变量或函数以及结构体首字母大写代表公有,小写代表私有

成员方法

//GetName 对象方法, 公有
func (p *person) GetName() string {
	return p.Name
}

Go通过这种复杂的形式来实现成员函数,更准确的说是结构体的方法,即为结构体赋予方法。

这样调用

p.GetName()

构造函数

构造函数用于对象初始化

//Person 构造函数
func Person(name string, age int) *person {
	return &person{Name: name, age: age}
}

这里其实是一个普通的函数,但是返回值是一个person结构体,功能上类似构造函数,因此可以作为'Person类'构造函数。

接口

//Sayer接口 定义
type Sayer interface {
	Say()
}

Go中的接口实现也是鸭子类型,即'类'只需实现该接口的方法,而无需显示继承接口,就可看作是该接口的子类型。

//say 实现接口
func (p *person) Say() {
	fmt.Println("My name is ", p.GetName())
}

静态方法和静态变量

Go中是没有静态这个概念的,但是我认为在Go中静态这个概念有点多余,因为完全可是将文件中的全局变量和全局函数看作'静态'。

继承

Go中没有继承的概念。但是根据组合聚合复用原则,通过struct的组合来替代继承,并且这样代码耦合度会更低。

// 看作Studnet类继承了Person类
type Student struct {
    person *person
}

多态

第一种多态,子类多态,直接使用interface来实现;

第二种多态,函数多态,Go没有,因为Go不能重载函数;

第三种,特设多态,Go没有,因为Go不能重载函数也就更不能重载运算符了。

泛型

至于泛型,更没有。

参考文章