我们都知道,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不能重载函数也就更不能重载运算符了。
泛型
至于泛型,更没有。