Go语言虽然不是纯粹的面向对象语言,但它通过结构体(struct)、接口(interface)和方法(method)提供了面向对象编程的能力。下面我将通过具体示例展示Go中如何实现类、封装、继承、多态以及构造函数等概念。
1. 类与封装
在Go中,使用结构体(struct)来定义"类",并通过大小写控制访问权限实现封装。
package main
import "fmt"
// Person 类(结构体)
type Person struct {
name string // 小写开头,私有字段(仅在当前包内可访问)
Age int // 大写开头,公共字段(可在其他包中访问)
}
// NewPerson 构造函数(工厂函数)
// 通常以New开头命名构造函数
func NewPerson(name string, age int) *Person {
return &Person{
name: name,
Age: age,
}
}
// GetName 获取name的方法(Getter)
// 由于name是私有的,需要通过方法访问
func (p *Person) GetName() string {
return p.name
}
// SetName 设置name的方法(Setter)
func (p *Person) SetName(name string) {
p.name = name
}
// Introduce 方法
func (p *Person) Introduce() {
fmt.Printf("大家好,我是%s,今年%d岁。\n", p.name, p.Age)
}
func main() {
// 使用构造函数创建Person实例
person := NewPerson("张三", 25)
// 访问公共字段
fmt.Println("年龄:", person.Age)
// 通过方法访问私有字段
fmt.Println("姓名:", person.GetName())
// 修改私有字段
person.SetName("李四")
// 调用方法
person.Introduce()
}
2. 继承(组合)
Go没有传统意义上的继承,而是通过结构体嵌入(embedding)实现组合。
package main
import "fmt"
// Animal 基类
type Animal struct {
name string
}
// NewAnimal 构造函数
func NewAnimal(name string) *Animal {
return &Animal{name: name}
}
// Speak 方法
func (a *Animal) Speak() {
fmt.Println(a.name, "发出声音")
}
// Eat 方法
func (a *Animal) Eat() {
fmt.Println(a.name, "正在吃东西")
}
// Dog 继承Animal
type Dog struct {
*Animal // 嵌入Animal,相当于继承
Breed string // 狗的品种
}
// NewDog 构造函数
func NewDog(name, breed string) *Dog {
return &Dog{
Animal: NewAnimal(name),
Breed: breed,
}
}
// Speak 方法重写
func (d *Dog) Speak() {
fmt.Println(d.name, "汪汪叫")
}
// Fetch 子类特有方法
func (d *Dog) Fetch() {
fmt.Println(d.name, "正在捡球")
}
func main() {
animal := NewAnimal("普通动物")
animal.Speak()
animal.Eat()
dog := NewDog("阿黄", "金毛")
dog.Speak() // 调用重写后的方法
dog.Eat() // 调用继承的方法
dog.Fetch() // 调用子类特有方法
// 通过嵌入字段访问基类字段
fmt.Println("狗的名字:", dog.name)
fmt.Println("狗的品种:", dog.Breed)
}
3. 多态(接口实现)
Go通过接口(interface)实现多态。
package main
import "fmt"
// Shape 接口
type Shape interface {
Area() float64
Perimeter() float64
}
// Rectangle 矩形类
type Rectangle struct {
width, height float64
}
// NewRectangle 构造函数
func NewRectangle(width, height float64) *Rectangle {
return &Rectangle{width, height}
}
// Area 实现Shape接口的方法
func (r *Rectangle) Area() float64 {
return r.width * r.height
}
// Perimeter 实现Shape接口的方法
func (r *Rectangle) Perimeter() float64 {
return 2 * (r.width + r.height)
}
// Circle 圆形类
type Circle struct {
radius float64
}
// NewCircle 构造函数
func NewCircle(radius float64) *Circle {
return &Circle{radius}
}
// Area 实现Shape接口的方法
func (c *Circle) Area() float64 {
return 3.14 * c.radius * c.radius
}
// Perimeter 实现Shape接口的方法
func (c *Circle) Perimeter() float64 {
return 2 * 3.14 * c.radius
}
// PrintShapeInfo 多态函数,接受任何实现了Shape接口的类型
func PrintShapeInfo(s Shape) {
fmt.Printf("面积: %.2f, 周长: %.2f\n", s.Area(), s.Perimeter())
}
func main() {
rect := NewRectangle(10, 5)
circle := NewCircle(7)
// 相同接口,不同表现
PrintShapeInfo(rect)
PrintShapeInfo(circle)
// 接口类型断言
if r, ok := rect.(*Rectangle); ok {
fmt.Println("这是一个矩形,宽:", r.width, "高:", r.height)
}
// 类型开关(type switch)
var s Shape = circle
switch v := s.(type) {
case *Rectangle:
fmt.Println("矩形:", v.width, v.height)
case *Circle:
fmt.Println("圆形,半径:", v.radius)
default:
fmt.Println("未知形状")
}
}
4. 方法实现细节
Go中的方法可以绑定到任何类型(不仅仅是结构体),包括基本类型。
package main
import (
"fmt"
"math"
)
// MyInt 自定义类型
type MyInt int
// Double 方法
func (m MyInt) Double() MyInt {
return m * 2
}
// Point 结构体
type Point struct {
X, Y float64
}
// DistanceTo 方法(值接收者)
func (p Point) DistanceTo(q Point) float64 {
return math.Hypot(q.X-p.X, q.Y-p.Y)
}
// Scale 方法(指针接收者,会修改原值)
func (p *Point) Scale(factor float64) {
p.X *= factor
p.Y *= factor
}
// String 方法(实现Stringer接口)
func (p Point) String() string {
return fmt.Sprintf("Point{X: %.2f, Y: %.2f}", p.X, p.Y)
}
func main() {
// 自定义类型方法
num := MyInt(5)
fmt.Println(num.Double()) // 10
// 结构体方法
p1 := Point{1, 2}
p2 := Point{4, 6}
fmt.Println("距离:", p1.DistanceTo(p2)) // 5
p1.Scale(2)
fmt.Println(p1) // 使用String方法输出: Point{X: 2.00, Y: 4.00}
// 指针与值的自动转换
p3 := &Point{3, 4}
fmt.Println("距离:", p3.DistanceTo(p2)) // Go会自动解引用
p2.Scale(0.5) // Go会自动取地址
fmt.Println(p2)
}
5. 综合示例
package main
import (
"fmt"
"strings"
)
// Employee 基类
type Employee struct {
name string
salary float64
vacation bool
}
// NewEmployee 构造函数
func NewEmployee(name string, salary float64) *Employee {
return &Employee{
name: name,
salary: salary,
vacation: false,
}
}
// GetName Getter
func (e *Employee) GetName() string {
return e.name
}
// GetSalary Getter
func (e *Employee) GetSalary() float64 {
return e.salary
}
// TakeVacation 方法
func (e *Employee) TakeVacation() {
e.vacation = true
}
// Work 方法
func (e *Employee) Work() {
fmt.Printf("%s 正在工作...\n", e.name)
}
// String 方法
func (e *Employee) String() string {
return fmt.Sprintf("员工: %s, 薪资: %.2f, 休假中: %v",
e.name, e.salary, e.vacation)
}
// Developer 子类
type Developer struct {
*Employee // 嵌入Employee
language string // 开发语言
}
// NewDeveloper 构造函数
func NewDeveloper(name string, salary float64, language string) *Developer {
return &Developer{
Employee: NewEmployee(name, salary),
language: language,
}
}
// Work 方法重写
func (d *Developer) Work() {
fmt.Printf("%s 正在用 %s 写代码...\n", d.GetName(), d.language)
}
// Debug 特有方法
func (d *Developer) Debug() {
fmt.Printf("%s 正在调试 %s 代码...\n", d.GetName(), d.language)
}
// Manager 子类
type Manager struct {
*Employee // 嵌入Employee
team []string // 团队成员
}
// NewManager 构造函数
func NewManager(name string, salary float64, team []string) *Manager {
return &Manager{
Employee: NewEmployee(name, salary),
team: team,
}
}
// Work 方法重写
func (m *Manager) Work() {
fmt.Printf("%s 正在管理团队: %s\n",
m.GetName(), strings.Join(m.team, ", "))
}
// ConductMeeting 特有方法
func (m *Manager) ConductMeeting() {
fmt.Printf("%s 正在主持会议\n", m.GetName())
}
// Worker 接口
type Worker interface {
Work()
GetName() string
GetSalary() float64
}
// Company 公司类
type Company struct {
workers []Worker
}
// AddWorker 添加员工
func (c *Company) AddWorker(w Worker) {
c.workers = append(c.workers, w)
}
// StartWorkDay 开始工作日
func (c *Company) StartWorkDay() {
fmt.Println("===== 工作日开始 =====")
for _, worker := range c.workers {
worker.Work()
}
fmt.Println("===== 工作日结束 =====")
}
func main() {
// 创建公司
company := &Company{}
// 创建员工
dev1 := NewDeveloper("张三", 15000, "Go")
dev2 := NewDeveloper("李四", 16000, "Python")
manager := NewManager("王五", 25000, []string{"张三", "李四"})
// 员工休假
dev1.TakeVacation()
// 添加员工到公司
company.AddWorker(dev1)
company.AddWorker(dev2)
company.AddWorker(manager)
// 开始工作
company.StartWorkDay()
// 调用特有方法
dev2.Debug()
manager.ConductMeeting()
// 打印员工信息
fmt.Println(dev1)
fmt.Println(dev2)
fmt.Println(manager)
}
关键概念总结
-
类与封装:Go使用结构体定义类,通过字段/方法名的大小写控制访问权限(大写公开,小写私有)
-
构造函数:Go没有真正的构造函数,通常使用
NewXxx
形式的工厂函数 -
继承:通过结构体嵌入实现组合式继承
-
多态:通过接口实现,任何实现了接口所有方法的类型都自动满足该接口
-
方法:可以绑定到任何类型,接收者可以是值或指针
-
接口:定义行为而非实现,是实现多态的关键
Go的面向对象方式与传统OOP语言有所不同,它更强调组合而非继承,通过接口实现多态,这种方式更灵活且避免了传统继承的许多问题。