介绍
封装(encapsulation)就是把抽象出来的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只有通过被授权的操作(方法),才能对字段进行操作。
栗子: 对电视机的操作就是典型的封装。
好处
- 隐藏实现的细节
-
怎么实现封装
对结构体中的属性进行封装
-
封装实现步骤
将结构体、字段(属性)的首字母小写(不能导出,私有private)
- 给结构体所在的包提供一个工厂模式的函数,首字母大写。(类似一个构造函数)
提供一个首字母大写的 Set 方法(公开public),用于对属性判断并赋值
func (var 结构体类型名) SetXxx(参数列表) (返回值列表) {
// 加入数据验证的业务逻辑
var.字段 = 参数
// return
}
提供一个首字母大写的 Get 方法(公开public),用于获取属性的值
func (var 结构体类型名) GetXxx(参数列表) (返回值列表) {
return var.字段
}
代码
对于nil,一般通常指针类型和interface类型可以使用这样的返回值
go_code/struct/encapsulation/main/main.go ```go package main
import ( “fmt” “go_code/struct/encapsulation/model” )
func main() { p := model.NewPerson(“tom”) // p.age = 18 // p.age undefined (cannot refer to unexported field or method age) p.SetAge(18) p.SetSal(20000) fmt.Println(“p = “, p) fmt.Println(“p.Name = “, p.Name) fmt.Println(“p.age = “, p.GetAge()) fmt.Println(“p.sal = “, p.GetSal()) }
go_code/struct/encapsulation/model/person.go
```go
// 该程序展示封装
package model
import "fmt"
type person struct {
Name string
// 以下字段不公开
age int
sal float64
}
// 工厂模式函数,让未公开的标识符可以被外部访问
func NewPerson(name string) *person {
return &person{
Name: name,
}
}
// 为了访问 age 和 sal 我们编写一堆 SetXxx、GetXxx方法
func (p *person) SetAge(age int) {
// 数据校验
if age > 0 && age < 150 {
p.age = age
} else {
fmt.Printf("年龄%v不合适", age)
}
}
func (p *person) GetAge() int {
return p.age
}
func (p *person) SetSal(sal float64) {
// 数据校验
if sal > 3000 && sal < 80000 {
p.sal = sal
} else {
fmt.Printf("薪水%v不合适", sal)
}
}
func (p *person) GetSal() float64 {
return p.sal
}
账户封装改造
go_code/struct/encapsulation02/main/main.go
package main
import (
"fmt"
"go_code/struct/encapsulation02/model"
)
func main() {
account := model.NewAccount("js123456", "888888", 22)
if account != nil {
fmt.Println("账户创建成功")
} else {
fmt.Println("账户创建失败")
}
fmt.Println("account = ", account)
}
go_code/struct/encapsulation02/model/account.go
package model
import "fmt"
// 定义一个 account 结构体
type account struct {
accountNo string
pwd string
blance float64
}
// 工厂模式的构造函数
func NewAccount(accountNo string, pwd string, blance float64) *account {
// 数据校验
if len(accountNo) < 6 || len(accountNo) > 10 {
fmt.Println("账号长度不对")
// 对于nil,一般通常指针类型和interface类型可以使用这样的返回值
return nil
}
if len(pwd) != 6 {
fmt.Println("密码长度不对")
return nil
}
if blance < 20 {
fmt.Println("余额不对")
return nil
}
return &account{
accountNo: accountNo,
pwd: pwd,
blance: blance,
}
}
// 绑定方法
// 1. 存款
func (account *account) Deposite(money float64, pwd string) {
// 判断输入的密码是否正确
if pwd != account.pwd {
fmt.Println("您输入的密码不正确")
return
}
// 校验金额
if money < 0 {
fmt.Println("金额不正确")
return
}
account.blance += money
fmt.Printf("存款成功,交易后余额: %v \n", account.blance)
}
// 2.取款
func (account *account) WithDraw(money float64, pwd string) {
// 判断输入的密码是否正确
if pwd != account.pwd {
fmt.Println("您输入的密码不正确")
return
}
// 校验金额
if money < 0 || money > account.blance {
fmt.Println("金额不正确")
return
}
account.blance -= money
fmt.Printf("取款成功,交易后余额: %v \n", account.blance)
}
// 2.查询余额
func (account *account) Query(pwd string) {
// 判断输入的密码是否正确
if pwd != account.pwd {
fmt.Println("您输入的密码不正确")
return
}
fmt.Printf("你的账号:%v, 余额: %v \n", account.accountNo, account.blance)
}