介绍

封装(encapsulation)就是把抽象出来的字段和对字段的操作封装在一起,数据被保护在内部,程序的其它包只有通过被授权的操作(方法),才能对字段进行操作。
栗子: 对电视机的操作就是典型的封装。

好处

  1. 隐藏实现的细节
  2. 可以对数据进行验证,保证安全合理

    怎么实现封装

  3. 对结构体中的属性进行封装

  4. 通过方法、包实现封装

    封装实现步骤

  5. 将结构体、字段(属性)的首字母小写(不能导出,私有private)

  6. 给结构体所在的包提供一个工厂模式的函数,首字母大写。(类似一个构造函数)
  7. 提供一个首字母大写的 Set 方法(公开public),用于对属性判断并赋值

    1. func (var 结构体类型名) SetXxx(参数列表) (返回值列表) {
    2. // 加入数据验证的业务逻辑
    3. var.字段 = 参数
    4. // return
    5. }
  8. 提供一个首字母大写的 Get 方法(公开public),用于获取属性的值

    1. func (var 结构体类型名) GetXxx(参数列表) (返回值列表) {
    2. return var.字段
    3. }

    代码

    对于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()) }

  1. go_code/struct/encapsulation/model/person.go
  2. ```go
  3. // 该程序展示封装
  4. package model
  5. import "fmt"
  6. type person struct {
  7. Name string
  8. // 以下字段不公开
  9. age int
  10. sal float64
  11. }
  12. // 工厂模式函数,让未公开的标识符可以被外部访问
  13. func NewPerson(name string) *person {
  14. return &person{
  15. Name: name,
  16. }
  17. }
  18. // 为了访问 age 和 sal 我们编写一堆 SetXxx、GetXxx方法
  19. func (p *person) SetAge(age int) {
  20. // 数据校验
  21. if age > 0 && age < 150 {
  22. p.age = age
  23. } else {
  24. fmt.Printf("年龄%v不合适", age)
  25. }
  26. }
  27. func (p *person) GetAge() int {
  28. return p.age
  29. }
  30. func (p *person) SetSal(sal float64) {
  31. // 数据校验
  32. if sal > 3000 && sal < 80000 {
  33. p.sal = sal
  34. } else {
  35. fmt.Printf("薪水%v不合适", sal)
  36. }
  37. }
  38. func (p *person) GetSal() float64 {
  39. return p.sal
  40. }

账户封装改造

go_code/struct/encapsulation02/main/main.go

  1. package main
  2. import (
  3. "fmt"
  4. "go_code/struct/encapsulation02/model"
  5. )
  6. func main() {
  7. account := model.NewAccount("js123456", "888888", 22)
  8. if account != nil {
  9. fmt.Println("账户创建成功")
  10. } else {
  11. fmt.Println("账户创建失败")
  12. }
  13. fmt.Println("account = ", account)
  14. }

go_code/struct/encapsulation02/model/account.go

  1. package model
  2. import "fmt"
  3. // 定义一个 account 结构体
  4. type account struct {
  5. accountNo string
  6. pwd string
  7. blance float64
  8. }
  9. // 工厂模式的构造函数
  10. func NewAccount(accountNo string, pwd string, blance float64) *account {
  11. // 数据校验
  12. if len(accountNo) < 6 || len(accountNo) > 10 {
  13. fmt.Println("账号长度不对")
  14. // 对于nil,一般通常指针类型和interface类型可以使用这样的返回值
  15. return nil
  16. }
  17. if len(pwd) != 6 {
  18. fmt.Println("密码长度不对")
  19. return nil
  20. }
  21. if blance < 20 {
  22. fmt.Println("余额不对")
  23. return nil
  24. }
  25. return &account{
  26. accountNo: accountNo,
  27. pwd: pwd,
  28. blance: blance,
  29. }
  30. }
  31. // 绑定方法
  32. // 1. 存款
  33. func (account *account) Deposite(money float64, pwd string) {
  34. // 判断输入的密码是否正确
  35. if pwd != account.pwd {
  36. fmt.Println("您输入的密码不正确")
  37. return
  38. }
  39. // 校验金额
  40. if money < 0 {
  41. fmt.Println("金额不正确")
  42. return
  43. }
  44. account.blance += money
  45. fmt.Printf("存款成功,交易后余额: %v \n", account.blance)
  46. }
  47. // 2.取款
  48. func (account *account) WithDraw(money float64, pwd string) {
  49. // 判断输入的密码是否正确
  50. if pwd != account.pwd {
  51. fmt.Println("您输入的密码不正确")
  52. return
  53. }
  54. // 校验金额
  55. if money < 0 || money > account.blance {
  56. fmt.Println("金额不正确")
  57. return
  58. }
  59. account.blance -= money
  60. fmt.Printf("取款成功,交易后余额: %v \n", account.blance)
  61. }
  62. // 2.查询余额
  63. func (account *account) Query(pwd string) {
  64. // 判断输入的密码是否正确
  65. if pwd != account.pwd {
  66. fmt.Println("您输入的密码不正确")
  67. return
  68. }
  69. fmt.Printf("你的账号:%v, 余额: %v \n", account.accountNo, account.blance)
  70. }