封装是面向对象的三大特性之一(封装、继承、多态),目的是隐藏实现细节、保护数据安全。
封装=隐藏数据+提供方法
核心规则:
- 通过包(package)控制访问权限
- 通过首字母大小写控制公开/私有
但是也有一种情况,比如在JSON序列化需要的时候,它的字段会大写,否则JSON序列化会忽略,
关键点:
| 场景 | 字段大小写 | 原因 |
|---|---|---|
| 内部 model | 小写 id |
私有数据,外部不直接访问 |
| 序列化输出 | 大写 ID |
需要导出给 JSON 编码器 |
内部model:
| 规则 | 示例 | 访问范围 |
|---|---|---|
| 大写开头 | SetPassword |
任何包都能访问 |
| 小写开头 | setPassword |
只有本包能访问 |
有封装和无封装的对比:
没有封装:
Go
// 任务数据裸露在外,任何人都可以直接修改
type Task struct {
ID uint
Title string
Status int // 0=待办,1=完成
}
// 任何人都可以直接改
task.Status = 100 // 状态值变成 100,逻辑上不对,但没人拦着
有封装:(隐藏细节)
Go
type Task struct {
id uint // 小写开头,外部看不到
title string // 小写开头,外部看不到
status int // 小写开头,外部看不到
}
// 只暴露安全的操作方法
func (t *Task) MarkDone() {
t.status = 1 // 内部修改
}
func (t *Task) IsDone() bool {
return t.status == 1 // 内部判断
}
字段封装:
Go
// model/user.go
type User struct {
gorm.Model
UserName string // 公开 - 别人可以看到用户名
PasswordDigest string // 公开 - 名字暴露了这是密码摘要
}
举个例子:(计数器)
定义一个结构体:
Go
type counter struct {
value int // 私有字段,外部无法直接访问
}
创建新的计数器:
Go
// 创建新的计数器
func New() *counter {
return &counter{value: 0}
}
通过方法来操作数据:
Go
// 只能通过方法操作数据
func (c *counter) Increment() {
c.value++
}
func (c *counter) Decrement() {
c.value--
}
func (c *counter) GetValue() int {
return c.value
}
使用示例:
Go
// 使用示例
func main() {
c := counter.New()
c.Increment()
c.Increment()
c.Decrement()
fmt.Println(c.GetValue()) // 输出: 1
// c.value = 100 // 错误!无法访问私有字段
}