介绍
封装(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 modelimport "fmt"type person struct {Name string// 以下字段不公开age intsal 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 mainimport ("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 modelimport "fmt"// 定义一个 account 结构体type account struct {accountNo stringpwd stringblance 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 += moneyfmt.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 -= moneyfmt.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)}
