这篇文章会聊到面向对象编程和Go 的面向对象编程,并尽可能的讲的通俗和有趣。

面向对象

什么是面向对象编程?

面向对象编程是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石 。实际上,面向对象编程从字面上,按照最简单、最原始的方式来理解,就是将对象或类作为代码组织的基本单元,来进行编程的一种编程范式或者编程风格,并不一定需要封装、抽象、继承、多态这四大特性的支持。

Go 的面相对象编程

在简单的解释了什么是面向对象编程后,我在这里直接为你展示,Go 的面相对象编程例子,方便你更好的理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type Animal interface {
Speak() string
}

type Dog struct{}

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

type Cat struct{}

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

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

上面可以说是你最常见过的代码了,Java 那边也经常用这样的代码进行讲解,不过我不会具体的讲解这里的代码,因为你应该要看的懂。

Go 语言不直接支持传统的面向对象编程,没有类和继承的概念,但通过结构体(struct)和接口(interface)实现了一些面向对象的特性。你可以使用结构体定义数据结构,通过方法(method)实现行为,并使用接口定义多态性。适合需要模拟现实世界对象和关系的场景,如游戏开发中的实体、用户管理系统等。

面向对象编程的简化理解

即使不考虑封装、抽象、继承和多态,面向对象编程仍然可以通过以下方式来理解:

  • 代码组织:以对象为基本单位进行代码组织,类定义了对象的结构和行为。
  • 数据与行为的组合:将数据(属性)和行为(方法)组合在一起,以对象的形式封装。
  • 对象交互:通过对象之间的交互来实现程序逻辑,而不是通过单纯的函数调用。

Go 的广义面向对象编程

从广义上来说,Go 可以被认为是一种支持面向对象编程(OOP)的编程语言。虽然 Go 没有传统面向对象编程语言中的类和继承,但它提供了结构体(struct)和接口(interface),这使得它能够实现许多面向对象的概念和模式。以下是一些支持这一观点的具体特性:

1. 结构体(Struct)

Go 使用结构体来定义数据类型,并可以为这些结构体定义方法。结构体类似于面向对象编程中的类,但没有继承的概念。

1
2
3
4
5
6
7
8
type Person struct {
Name string
Age int
}

func (p Person) Greet() string {
return "Hello, my name is " + p.Name
}

2. 方法(Methods)

Go 允许为任意类型(包括结构体类型)定义方法。这些方法可以看作是结构体的行为。

1
2
3
func (p Person) Greet() string {
return "Hello, my name is " + p.Name
}

3. 接口(Interfaces)

Go 的接口提供了一种方式来定义行为,并允许不同的类型实现这些接口。接口在 Go 中非常强大,因为它们支持多态性。

1
2
3
4
5
6
7
8
9
10
11
12
type Greeter interface {
Greet() string
}

func greet(g Greeter) {
fmt.Println(g.Greet())
}

func main() {
p := Person{Name: "Alice", Age: 30}
greet(p) // 输出: Hello, my name is Alice
}

4. 嵌入(Embedding)

Go 支持嵌入,这可以看作是组合而不是继承的一种方式,使得我们可以重用代码。

1
2
3
4
5
6
7
8
9
type Employee struct {
Person
Position string
}

func main() {
e := Employee{Person: Person{Name: "Bob", Age: 25}, Position: "Developer"}
fmt.Println(e.Greet()) // 输出: Hello, my name is Bob
}

5. 多态性(Polymorphism)

通过接口,Go 实现了多态性,不同类型可以实现相同的接口,从而在不修改代码的情况下实现行为的替换。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Dog struct{}

func (d Dog) Greet() string {
return "Woof"
}

func main() {
var g Greeter
g = Person{Name: "Alice", Age: 30}
fmt.Println(g.Greet()) // 输出: Hello, my name is Alice

g = Dog{}
fmt.Println(g.Greet()) // 输出: Woof
}

封装、抽象、继承、多态

接下来会详细的聊一下,普遍认知中的面向对象四大特性,理解面向对象编程及 Go 语言中面向对象编程概念的关键就是理解这四大特性: 封装、抽象、继承、多态。过程中会介绍 Go 语言中,如何体现这四大特性。

封装

接下来简单介绍封装特性。封装也叫作信息隐藏或者数据访问保护。对象或类通过暴露有限的访问接口,授权外部仅能通过类提供的方式 (或者叫函数) 来访问内部信息或者数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import "fmt"

// Counter 结构体
type Counter struct {
value int
}

// NewCounter 构造函数,初始化一个新的 Counter
func NewCounter() *Counter {
return &Counter{value: 0}
}

// Increment 方法,用于增加计数器的值
func (c *Counter) Increment() {
c.value++
}

// Value 方法,用于获取当前计数器的值
func (c *Counter) Value() int {
return c.value
}

func main() {
c := NewCounter() // 创建一个新的 Counter 实例

c.Increment() // 增加计数器的值
c.Increment()

fmt.Println("Counter value:", c.Value()) // 输出: Counter value: 2
}
  1. 数据隐藏

    • Counter 结构体的 value 字段是不可访问的(小写字母开头),只能在 Counter 结构体内部访问。
    • 外部代码无法直接修改 value 的值,保护了数据的完整性。
  2. 通过方法访问数据

    • Increment 方法是可访问的,用于增加计数器的值。

    • Value 方法是可访问的,用于获取当前计数器的值。

封装的意义
  1. 数据隐藏value 字段被隐藏,防止外部直接访问和修改,保护数据的完整性。
  2. 控制访问权限:通过 IncrementValue 方法控制对计数器的操作。
  3. 提高代码的可维护性:封装实现细节,外部代码不需要关心计数器的内部实现,只需要调用提供的方法。

抽象

… 未完待续