作为当下比较热门的编程语言,社区中也时不时有针对Go 面向对象编程的讨论。俺整理了一部分有价值的内容,供大家参考。

pushing-cart (配图来自:gophers

Go 是面向对象语言么?

faq

是和否。 尽管 Go 有类型和方法,并允许面向对象的编程风格,但没有类型层次结构。 Go 中“接口”的概念提供了一种不同的方法,我们认为它易于使用,并且在某些方面更通用。 还有一些方法可以将类型嵌入到其他类型中,以提供与子类化类似但不完全相同的东西。 此外,Go 中的方法比 C++ 或 Java 中的方法更通用:它们可以为任何类型的数据定义,甚至是内置类型,例如普通的“未装箱”整数。 它们不限于结构(类)。 此外,由于缺乏类型层次结构,Go 中的“对象”感觉比 C++ 或 Java 等语言轻得多。

为何没有类(class)?

面向对象讨论 v友讨论

大多数人所谓的 OOP,其实都是说的“继承封装多态”这一套,但是,最早的 OOP 叫对象范式,对象范式的两个基本观念:

  • 程序是由对象组成的;
  • 对象之间互相发送消息,协作完成任务;

请问,有“继承、封装、多态”的定义吗?没有!!!这两个观念与后来我们熟知的面向对象三要素“封装、继承、多态”根本不在一个层面上。倒是与再后来的“组件、接口”神合。

那 Go 中怎么满足上面两点的呢,我们可以使用 struct 来表示对象。

func main() {
	dog := Dog{Breed: "husky", Color: "black and white"}
	fmt.Println(dog.Breed)
	fmt.Println(dog.Speak())
}

type Dog struct {
	Breed string
	Color string
}

func (d Dog) Speak() string {
	return "Woof!"
}

上面声明了 Dog 结构体,包含品种和颜色两个属性,另外给 Dog 增加了说话的方法。

按照上面的理念,我们定义husky为字符串类型,同样增加了说话的方法,问:husky是对象么?

当然是,虽然它内部只能维护一个变量。

func main() {
	h := husky("stupid dog")
	fmt.Println(h)
	fmt.Println(h.Speak())
}

type husky string

func (h husky) Speak() string {
	return "Woof!"
}

“继承、封装、多态” 在Go中如何实现?

继承

Go 没有 extends 关键字显式声明继承关系,不过可以通过内嵌匿名成员方式达到继承目的。

我们来看以下代码:

type Superpower struct {
	name string
}

func (s Superpower) Biu() string {
	return "Biu biu biu!"
}

type Dog struct {
	Breed string
	Color string
	Superpower
}

func (d Dog) Speak() string {
	return "Woof!"
}

将 Superpower 嵌入 Dog 中即可使用 Superpower 的方法和属性。

dog := Dog{}
fmt.Println(dog.Biu())

封装

在 Go 语言中没有 public、private、protected 这样的访问控制修饰符,它是通过字母大小写来控制可见性的。

如果定义的常量、变量、类型、接口、结构、函数等的名称是大写字母开头,这表示它们能被其它包访问或调用(相当于 public);非大写开头就只能在包内使用(相当于 private)。

示例代码:

type Dog struct {
	breed string
	Color string
	Superpower
}

func (d Dog) Speak() string {
	return "Woof!"
}

func (d Dog) GetBreed() string {
	return d.breed
}

func (d Dog) SetBreed(breed string) {
	d.breed = breed
}

多态

在面向对象中,多态的特征为:不同对象中同种行为的不同实现方式。在 Go 语言中可以使用接口实现这一特征。

Go 中没有 implements 关键字;类型是否满足接口是自动确定的。如下代码,Dog 实现了 Speak 方法即实现了 Animal 接口。

type Animal interface {
	Speak() string
}

type Superpower struct {
	name string
}

func (s Superpower) Biu() string {
	return "Biu biu biu!"
}

type Dog struct {
	Breed string
	Color string
	Superpower
}

func (d Dog) Speak() string {
	return "Woof!"
}

type Cat struct {
	Breed string
	Color string
	Superpower
}

func (c Cat) Speak() string {
	return "Meow!!"
}

func main() {
	dog := Dog{Breed: "husky", Color: "black and white", Superpower: Superpower{
		name: "biu",
	}}
	fmt.Println(dog.name)
	fmt.Println(dog.Biu())

	animals := []Animal{Dog{}, Cat{}}
	for _, animal := range animals {
		fmt.Println(animal.Speak())
	}
}

总结

Go 可以以面向对象方式编程,使用 struct 封装状态,interface 封装行为。

Reference