书接上回,我们之前基本聊的是golang的基本类型。结构体(struct)聚合了不同类型的数据。
之前的这些基本都是面向过程的编程范式的内容。
接下来,我们将开始面向对象的编程范式。
面向对象编程,最有代表性的编程语言是C++,它提供了class这个关键字来代表类,我是通过C++,知晓了类的构造/析构,成员变量,成员函数,操作符重载,继承,多态,封装,接口,多父类,this, super等概念,还有public, private, friend等可见性属性, static, const等变量修饰符。以及后续的单例/观察者/装饰等24个设计模式。
面向对象编程,实际上提供了另一种与面向过程所不同的编程视角。
面向过程是对需要处理的问题分解成一个个需要处理的小一点的问题,最终以一个个处理的过程(函数)的形式存在。过程与过程之间是不断调用的处理流程。面向过程编程的基本单元是函数(function)。golang中对面向过程的支持是使用func关键字定义一个个函数。
面向对象是将一系列相关的处理过程和相关字段整合成一个可以视为单独对待的实体,这个实体有自己的数据,有自己的可以被操作的行为(对外公布)。某种程度上,就像把这样的实体当成一个可以独立存在的事物,有点像人。我们知道它的一些属性,一些它能做的事情。然后,我们去构建它,使用它(调用它的公共方法)。这提供的是一个更大粒度的代码组织单元,这就是类(class)。C++的出目前当时给人们提供了解决大规模代码模块化的更有效方式。
作为程序员,我们使用面向对象的范式进行编程,主要是由于它提供了一个更大颗粒度的代码组织方式。我们只需要把处理的问题组织成一个个不同的独特的类,和这些类之间的交互的过程。
相对于面向过程,这是一种更高粒度/维度的思维方式。相应的,它也提供了复杂性。
golang中没有提供class关键字,实际上,golang中只实现了基于对象的编程方式,它有意的降低/避免了面向对象的复杂性。
golang中使用结构体,并给结构体提供成员方法的方式,实现了一个类的属性和行为。
type Cat struct {
Name string
Age int
}
// 值接收
func (c Cat) Speak() {
fmt.Println("喵喵喵")
}
// 指针接收
func (c *Cat) Grow() {
c.Age++
}
值接收方法不会修改原始对象,而指针接收方法可以直接修改对象的属性。
这样实现的golang类,实际上是一种实体类。
golang另外提供了interface关键字,用于定义接口,用来实现更多的面向对象特性。
接口定义了一系列方法(行为)的组合,定义了一个抽象类应该具备的行为约定。
我们回到之前的基本数据类型,实际上我们在使用基本数据类型时,也常常有意无意的把它们也当成一个个具备特性行为的”类型“,我们知道它们有的接口(行为),然后去使用它们。
接口类型提供了这样一个类的行为界面,它告知我们一个这样的”实体”应该是什么样子的。
type Shape interface {
Area() float64
Perimeter() float64
}
golang中类实现一个接口,只需要具备这个接口的所有的方法(行为),没有像c++, java那样显示的定义。因此,在golang中,只要你表现出鸭子的行为,你在某种程度上你就是鸭子。
golang用这种方式,简化了面向对象编程,某种程度上,golang实现的是面向接口编程。
总结一下,在golang中,我们更多的是定义一个个抽象的接口,然后去定义实现这些接口行为的实体类,对继承使用不是许多,只是在有限的场景有限的使用。这规避了面向对象编程的复杂性,同时也比面向过程更加灵活,和更大的代码组织粒度。
golang是一种工程编程语言,实至名归。
从明天开始,我们进入golang最具魅力的部分:并发。


