1. 项目开发流程
  2. 项目需求
  3. 项目界面
  4. 项目代码实现
    1. 先使用面向过程,后改为面向对象

image.png
项目金额预估 = 人员+时间+软硬件设备+buffer

项目需求

  1. 模拟实现基于文本界面的《家庭记账软件》
  2. 该软件能够记录家庭的收入、支出,并能够打印收支明细表
  3. 项目界面(类似于ATM机上的功能)

image.png
image.png

面向过程

  1. 先完成可以显示主菜单,并且可以退出
  2. 完成可以显示明细的功能
  3. 完成登记收入的功能
  4. 完成登记支出的功能

    代码

    ```go // 家庭收支记账软件 - 面向过程实现 package main

import ( “fmt” )

func main() { // 声明变量,接收用户输入菜单项 key := “” // 声明变量,控制是否退出for loop := true

  1. // 定义账户余额
  2. blance := 1000.0
  3. // 每次收支的金额
  4. money := 0.0
  5. //收支说明
  6. note := ""
  7. // 定义一个变量,表示是否存在收支记录
  8. flag := false
  9. // 收支详情,使用字符串记录
  10. // 当有收支记录的时候,只需要对 details 拼接即可
  11. details := "收支\t账户金额\t收支金额\t说明"
  12. // 显示主菜单
  13. for {
  14. fmt.Println("***********************家庭收支记账软件***********************")
  15. fmt.Println(" 1、收支明细")
  16. fmt.Println(" 2、登记收入")
  17. fmt.Println(" 3、登记支出")
  18. fmt.Println(" 4、退出软件")
  19. fmt.Print("请选择(1-4): ")
  20. fmt.Scanln(&key)
  21. switch key {
  22. case "1":
  23. if !flag {
  24. fmt.Println("目前为止,你还没有收支记录,来一笔吧🎈")
  25. } else {
  26. fmt.Println("***********************当前收支明细记录***********************")
  27. fmt.Println(details)
  28. }
  29. case "2":
  30. fmt.Println("***********************登记收入***********************")
  31. fmt.Println("本次收入金额: ")
  32. fmt.Scanln(&money)
  33. fmt.Println("本次收入说明: ")
  34. fmt.Scanln(&note)
  35. blance += money
  36. details += fmt.Sprintf("\n收入\t%v\t\t%v\t\t%v", blance, money, note)
  37. flag = true
  38. case "3":
  39. fmt.Println("***********************登记支出***********************")
  40. fmt.Println("本次支出金额")
  41. fmt.Scanln(&money)
  42. if money > blance {
  43. fmt.Println("余额不足啦")
  44. break
  45. }
  46. blance -= money
  47. fmt.Println("本次收入说明: ")
  48. fmt.Scanln(&note)
  49. details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v", blance, money, note)
  50. flag = true
  51. case "4":
  52. fmt.Println("你确定退出吗,请输入:Y(是)/N(否)")
  53. choice := ""
  54. for {
  55. fmt.Scanln(&choice)
  56. if choice == "Y" || choice == "N" {
  57. break
  58. }
  59. fmt.Println("你的输入有误,请重新输入:Y/N")
  60. }
  61. if choice == "Y" {
  62. loop = false
  63. }
  64. }
  65. if !loop {
  66. break
  67. }
  68. fmt.Println()
  69. fmt.Println()
  70. }
  71. fmt.Println("你退出了家庭记账软件🤞")

}

  1. <a name="nF1Ye"></a>
  2. # 面向过程修改成面向对象
  3. 抽象思维<br />封装-继承-多态
  4. <a name="qFYYh"></a>
  5. ## 思路分析
  6. 1. 把记账软件的功能,封装到一个结构体中,然后调用该结构的方法,来实现**记账**,**显示明细**。结构体的名字 **FamilyAccount**
  7. 2. 再通过在 **main** 方法中,创建结构体 **FamilyAccount 实例**,实现记账即可。
  8. 3. 代码不需要重写,只需要重新组织
  9. <a name="T3ziY"></a>
  10. ## 代码实现
  11. <a name="kL8ea"></a>
  12. ### familyAccount/utils/familyAccount.go
  13. ```go
  14. // 面向对象的方式实现 家庭记账软件
  15. // 封装、继承、多态
  16. package utils
  17. import (
  18. "fmt"
  19. )
  20. type FamilyAccount struct {
  21. // 声明必须的字段
  22. // 声明字段,接收用户输入菜单项
  23. key string
  24. // 声明字段,控制是否退出for
  25. loop bool
  26. // 定义账户余额
  27. blance float64
  28. // 每次收支的金额
  29. money float64
  30. //收支说明
  31. note string
  32. // 定义一个字段,表示是否存在收支记录
  33. flag bool
  34. // 收支详情,使用字符串记录
  35. // 当有收支记录的时候,只需要对 details 拼接即可
  36. details string
  37. // details := "收支\t账户金额\t收支金额\t说明"
  38. }
  39. // 编写一个工厂模式的构造函数,返回 FamilyAccount
  40. func NewFamilyAccount() *FamilyAccount {
  41. // 给定初始值
  42. return &FamilyAccount{
  43. key: "",
  44. loop: true,
  45. blance: 1000.0,
  46. money: 0.0,
  47. note: "",
  48. flag: false,
  49. details: "收支\t账户金额\t收支金额\t说明",
  50. }
  51. }
  52. // 将每个菜单的功能封装成一个方法
  53. // 明细
  54. func (account *FamilyAccount) ShowDetails() {
  55. if !account.flag {
  56. fmt.Println("目前为止,你还没有收支记录,来一笔吧🎈")
  57. } else {
  58. fmt.Println("***********************当前收支明细记录***********************")
  59. fmt.Println(account.details)
  60. }
  61. }
  62. // 登记收入方法
  63. func (account *FamilyAccount) Income() {
  64. fmt.Println("***********************登记收入***********************")
  65. fmt.Println("本次收入金额: ")
  66. fmt.Scanln(&account.money)
  67. fmt.Println("本次收入说明: ")
  68. fmt.Scanln(&account.note)
  69. account.blance += account.money
  70. account.details += fmt.Sprintf("\n收入\t%v\t\t%v\t\t%v", account.blance, account.money, account.note)
  71. account.flag = true
  72. }
  73. // 登记支出方法
  74. func (account *FamilyAccount) Pay() {
  75. fmt.Println("***********************登记支出***********************")
  76. fmt.Println("本次支出金额")
  77. fmt.Scanln(&account.money)
  78. if account.money > account.blance {
  79. fmt.Println("余额不足啦")
  80. // break
  81. }
  82. account.blance -= account.money
  83. fmt.Println("本次收入说明: ")
  84. fmt.Scanln(&account.note)
  85. account.details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v", account.blance, account.money, account.note)
  86. account.flag = true
  87. }
  88. // 退出方法
  89. func (account *FamilyAccount) Exit() {
  90. fmt.Println("你确定退出吗,请输入:Y(是)/N(否)")
  91. choice := ""
  92. for {
  93. fmt.Scanln(&choice)
  94. if choice == "Y" || choice == "N" {
  95. break
  96. }
  97. fmt.Println("你的输入有误,请重新输入:Y/N")
  98. }
  99. if choice == "Y" {
  100. account.loop = false
  101. }
  102. }
  103. // 给 FamilyAccount 结构体绑定方法
  104. // 显示主菜单
  105. func (account *FamilyAccount) MainMenu() {
  106. for {
  107. fmt.Println("***********************家庭收支记账软件***********************")
  108. fmt.Println(" 1、收支明细")
  109. fmt.Println(" 2、登记收入")
  110. fmt.Println(" 3、登记支出")
  111. fmt.Println(" 4、退出软件")
  112. fmt.Print("请选择(1-4): ")
  113. fmt.Scanln(&account.key)
  114. switch account.key {
  115. case "1":
  116. account.ShowDetails()
  117. case "2":
  118. account.Income()
  119. case "3":
  120. account.Pay()
  121. case "4":
  122. account.Exit()
  123. }
  124. if !account.loop {
  125. break
  126. }
  127. fmt.Println()
  128. fmt.Println()
  129. }
  130. fmt.Println("你退出了家庭记账软件🤞")
  131. }

familyAccount/main/main.go

  1. // 面向对象方式完成调用
  2. package main
  3. import (
  4. _ "fmt"
  5. "go_code/familyAccount/utils"
  6. )
  7. func main() {
  8. // account := utils.NewFamilyAccount()
  9. // fmt.Println("account = ", *account)
  10. // true 1000 0 false 收支 账户金额 收支金额 说明}
  11. utils.NewFamilyAccount().MainMenu()
  12. }