家庭收支记账软件项目

项目开发流程说明

  1. 项目开发流程

    • 需求分析 -> 设计阶段 -> 实现阶段 -> 测试阶段 -> 项目实施 -> 维护阶段

      项目需求说明

  2. 模拟实现基于文本界面的《家庭记账软件》

  3. 该软件能够记录家庭的收入、支出,并能够打印收支明细表。

    项目的界面

  4. 项目采用分级菜单方式。

    项目代码实现

    实现基本功能(先使用面向过程,后面改成面向对象)

    编写文件 TestMyAccount.go 完成基本功能

  5. 功能一:先完成可以显示主菜单,并且可以退出。

    • 思路分析:根据给出界面完成主菜单的显示,当用户输入 4 时,就退出程序。 ```go package main

import “fmt”

func main() { //声明一个变量,保存接收用户输入的选项 key := “” //声明一个变量,控制是否退出 for loop := true //显示主菜单 for { fmt.Println(“——————家庭收支记账软件——————“) fmt.Println(“ 1 收支明细”) fmt.Println(“ 2 登记收入”) fmt.Println(“ 3 登记支出”) fmt.Println(“ 4 退出软件”) fmt.Print(“请选择(1-4): “)

  1. fmt.Scanln(&key)
  2. switch key {
  3. case "1":
  4. fmt.Println("------------当前收支明细记录------------")
  5. case "2":
  6. fmt.Println("登记收入..")
  7. case "3":
  8. fmt.Println("登记支出..")
  9. case "4":
  10. loop = false
  11. default:
  12. fmt.Println("请输入正确选项..")
  13. }
  14. if !loop {
  15. break
  16. }
  17. }
  18. fmt.Println("你退出家庭记账软件的使用..")

}

  1. 2. 功能二:完成可以显示明细和登记收入的功能
  2. - 思路分析
  3. - 因为需要显示明细,我们定义一个变量 details string 来记录
  4. - 还需要定义变量来记录余额(balance)、每次收支金额(money),每次收支的说明(note)
  5. ```go
  6. package main
  7. import "fmt"
  8. func main() {
  9. //声明一个变量,保存接收用户输入的选项
  10. key := ""
  11. //声明一个变量,控制是否退出 for
  12. loop := true
  13. //定义账户的余额
  14. balance := 10000.0
  15. //每次收支的金额
  16. money := 0.0
  17. //每次收支的说明
  18. note := ""
  19. //收支的详情使用字符串来记录
  20. //当有收支时,只需要对 details 拼接处理即可
  21. details := "收支\t\t账户余额\t\t收支金额\t\t说明"
  22. //显示主菜单
  23. for {
  24. fmt.Println("\n------------家庭收支记账软件------------")
  25. fmt.Println(" 1 收支明细")
  26. fmt.Println(" 2 登记收入")
  27. fmt.Println(" 3 登记支出")
  28. fmt.Println(" 4 退出软件")
  29. fmt.Print("请选择(1-4): ")
  30. fmt.Scanln(&key)
  31. switch key {
  32. case "1":
  33. fmt.Println("------------当前收支明细记录------------")
  34. fmt.Println(details)
  35. case "2":
  36. fmt.Println("登记收入..")
  37. fmt.Println("本次收入金额:")
  38. fmt.Scanln(&money)
  39. balance += money //修改账户余额
  40. fmt.Println("本次收入说明:")
  41. fmt.Scanln(&note)
  42. //将这个收入情况,拼接到 details 变量
  43. details += fmt.Sprintf("\n收入\t\t%v\t\t%v\t\t%v", balance, money, note)
  44. case "3":
  45. fmt.Println("登记支出..")
  46. fmt.Println("本次收入金额:")
  47. case "4":
  48. loop = false
  49. default:
  50. fmt.Println("请输入正确选项..")
  51. }
  52. if !loop {
  53. break
  54. }
  55. }
  56. fmt.Println("你退出家庭记账软件的使用..")
  57. }
  1. 功能三:完成了等级支出的功能
    • 思路分析:
      • 登记支出和登记收入的功能类似,做一些修改即可。 ```go package main

import “fmt”

func main() { //声明一个变量,保存接收用户输入的选项 key := “” //声明一个变量,控制是否退出 for loop := true //定义账户的余额 balance := 10000.0 //每次收支的金额 money := 0.0 //每次收支的说明 note := “” //收支的详情使用字符串来记录 //当有收支时,只需要对 details 拼接处理即可 details := “收支\t\t账户余额\t\t收支金额\t\t说明” //显示主菜单 for { fmt.Println(“\n——————家庭收支记账软件——————“) fmt.Println(“ 1 收支明细”) fmt.Println(“ 2 登记收入”) fmt.Println(“ 3 登记支出”) fmt.Println(“ 4 退出软件”) fmt.Print(“请选择(1-4): “)

  1. fmt.Scanln(&key)
  2. switch key {
  3. case "1":
  4. fmt.Println("------------当前收支明细记录------------")
  5. fmt.Println(details)
  6. case "2":
  7. fmt.Println("登记收入..")
  8. fmt.Println("本次收入金额:")
  9. fmt.Scanln(&money)
  10. balance += money //修改账户余额
  11. fmt.Println("本次收入说明:")
  12. fmt.Scanln(&note)
  13. //将这个收入情况,拼接到 details 变量
  14. details += fmt.Sprintf("\n收入\t\t%v\t\t%v\t\t%v", balance, money, note)
  15. case "3":
  16. fmt.Println("登记支出..")
  17. fmt.Println("本次支出金额:")
  18. fmt.Scanln(&money)
  19. //这里需要做必要的判断
  20. if money > balance {
  21. fmt.Println("余额不足..")
  22. break
  23. } else {
  24. balance -= money
  25. }
  26. fmt.Println("本次支出说明:")
  27. fmt.Scanln(&note)
  28. //将这个支出情况,拼接到 details 变量
  29. details += fmt.Sprintf("\n支出\t\t%v\t\t%v\t\t%v", balance, money, note)
  30. case "4":
  31. loop = false
  32. default:
  33. fmt.Println("请输入正确选项..")
  34. }
  35. if !loop {
  36. break
  37. }
  38. }
  39. fmt.Println("你退出家庭记账软件的使用..")

}

  1. <a name="81a8c974"></a>
  2. #### 项目代码实现改进
  3. 1. 用户输入 4 退出时,给出提示:你确定要退出吗?y/n,必须输入正确的y/n,否则循环输入指令,直到输入 y 或者 n。
  4. ```go
  5. package main
  6. import "fmt"
  7. func main() {
  8. //声明一个变量,保存接收用户输入的选项
  9. key := ""
  10. //声明一个变量,控制是否退出 for
  11. loop := true
  12. //定义账户的余额
  13. balance := 10000.0
  14. //每次收支的金额
  15. money := 0.0
  16. //每次收支的说明
  17. note := ""
  18. //收支的详情使用字符串来记录
  19. //当有收支时,只需要对 details 拼接处理即可
  20. details := "收支\t\t账户余额\t\t收支金额\t\t说明"
  21. //显示主菜单
  22. for {
  23. fmt.Println("\n------------家庭收支记账软件------------")
  24. fmt.Println(" 1 收支明细")
  25. fmt.Println(" 2 登记收入")
  26. fmt.Println(" 3 登记支出")
  27. fmt.Println(" 4 退出软件")
  28. fmt.Print("请选择(1-4): ")
  29. fmt.Scanln(&key)
  30. switch key {
  31. case "1":
  32. fmt.Println("------------当前收支明细记录------------")
  33. fmt.Println(details)
  34. case "2":
  35. fmt.Println("登记收入..")
  36. fmt.Println("本次收入金额:")
  37. fmt.Scanln(&money)
  38. balance += money //修改账户余额
  39. fmt.Println("本次收入说明:")
  40. fmt.Scanln(&note)
  41. //将这个收入情况,拼接到 details 变量
  42. details += fmt.Sprintf("\n收入\t\t%v\t\t%v\t\t%v", balance, money, note)
  43. case "3":
  44. fmt.Println("登记支出..")
  45. fmt.Println("本次支出金额:")
  46. fmt.Scanln(&money)
  47. //这里需要做必要的判断
  48. if money > balance {
  49. fmt.Println("余额不足..")
  50. break
  51. } else {
  52. balance -= money
  53. }
  54. fmt.Println("本次支出说明:")
  55. fmt.Scanln(&note)
  56. //将这个支出情况,拼接到 details 变量
  57. details += fmt.Sprintf("\n支出\t\t%v\t\t%v\t\t%v", balance, money, note)
  58. case "4":
  59. fmt.Println("你确定要退出吗?y/n")
  60. choice := ""
  61. for {
  62. fmt.Scanln(&choice)
  63. if choice == "y" || choice == "n" {
  64. break
  65. }
  66. fmt.Println("你的输入有误,请重新输入 y/n")
  67. }
  68. if choice == "y" {
  69. loop = false
  70. }
  71. default:
  72. fmt.Println("请输入正确选项..")
  73. }
  74. if !loop {
  75. break
  76. }
  77. }
  78. fmt.Println("你退出家庭记账软件的使用..")
  79. }
  1. 当没有任何收支明细时,提示:当前没有收支明细…来一笔吧! ```go package main

import “fmt”

func main() { //声明一个变量,保存接收用户输入的选项 key := “” //声明一个变量,控制是否退出 for loop := true //定义账户的余额 balance := 10000.0 //每次收支的金额 money := 0.0 //每次收支的说明 note := “” //收支的详情使用字符串来记录 //当有收支时,只需要对 details 拼接处理即可 details := “收支\t\t账户余额\t\t收支金额\t\t说明” //定义一个变量,记录是否有收支行为 flags := false //显示主菜单 for { fmt.Println(“\n——————家庭收支记账软件——————“) fmt.Println(“ 1 收支明细”) fmt.Println(“ 2 登记收入”) fmt.Println(“ 3 登记支出”) fmt.Println(“ 4 退出软件”) fmt.Print(“请选择(1-4): “)

  1. fmt.Scanln(&key)
  2. switch key {
  3. case "1":
  4. fmt.Println("------------当前收支明细记录------------")
  5. if flags {
  6. fmt.Println(details)
  7. } else {
  8. fmt.Println("当前没有收支明细...来一笔吧!")
  9. }
  10. case "2":
  11. fmt.Println("本次收入金额:")
  12. fmt.Scanln(&money)
  13. balance += money //修改账户余额
  14. fmt.Println("本次收入说明:")
  15. fmt.Scanln(&note)
  16. //将这个收入情况,拼接到 details 变量
  17. details += fmt.Sprintf("\n收入\t\t%v\t\t%v\t\t%v", balance, money, note)
  18. flags = true
  19. case "3":
  20. fmt.Println("本次支出金额:")
  21. fmt.Scanln(&money)
  22. //这里需要做必要的判断
  23. if money > balance {
  24. fmt.Println("余额不足..")
  25. break
  26. } else {
  27. balance -= money
  28. }
  29. fmt.Println("本次支出说明:")
  30. fmt.Scanln(&note)
  31. //将这个支出情况,拼接到 details 变量
  32. details += fmt.Sprintf("\n支出\t\t%v\t\t%v\t\t%v", balance, money, note)
  33. flags = true
  34. case "4":
  35. fmt.Println("你确定要退出吗?y/n")
  36. choice := ""
  37. for {
  38. fmt.Scanln(&choice)
  39. if choice == "y" || choice == "n" {
  40. break
  41. }
  42. fmt.Println("你的输入有误,请重新输入 y/n")
  43. }
  44. if choice == "y" {
  45. loop = false
  46. }
  47. default:
  48. fmt.Println("请输入正确选项..")
  49. }
  50. if !loop {
  51. break
  52. }
  53. }
  54. fmt.Println("你退出家庭记账软件的使用..")

}

  1. 3. 在支出时,判断余额是否足够,并给出相应的提示。
  2. ```go
  3. package main
  4. import "fmt"
  5. func main() {
  6. //声明一个变量,保存接收用户输入的选项
  7. key := ""
  8. //声明一个变量,控制是否退出 for
  9. loop := true
  10. //定义账户的余额
  11. balance := 10000.0
  12. //每次收支的金额
  13. money := 0.0
  14. //每次收支的说明
  15. note := ""
  16. //收支的详情使用字符串来记录
  17. //当有收支时,只需要对 details 拼接处理即可
  18. details := "收支\t\t账户余额\t\t收支金额\t\t说明"
  19. //定义一个变量,记录是否有收支行为
  20. flags := false
  21. //显示主菜单
  22. for {
  23. fmt.Println("\n------------家庭收支记账软件------------")
  24. fmt.Println(" 1 收支明细")
  25. fmt.Println(" 2 登记收入")
  26. fmt.Println(" 3 登记支出")
  27. fmt.Println(" 4 退出软件")
  28. fmt.Print("请选择(1-4): ")
  29. fmt.Scanln(&key)
  30. switch key {
  31. case "1":
  32. fmt.Println("------------当前收支明细记录------------")
  33. if flags {
  34. fmt.Println(details)
  35. } else {
  36. fmt.Println("当前没有收支明细...来一笔吧!")
  37. }
  38. case "2":
  39. fmt.Println("本次收入金额:")
  40. fmt.Scanln(&money)
  41. balance += money //修改账户余额
  42. fmt.Println("本次收入说明:")
  43. fmt.Scanln(&note)
  44. //将这个收入情况,拼接到 details 变量
  45. details += fmt.Sprintf("\n收入\t\t%v\t\t%v\t\t%v", balance, money, note)
  46. flags = true
  47. case "3":
  48. fmt.Println("本次支出金额:")
  49. fmt.Scanln(&money)
  50. //这里需要做必要的判断
  51. if money > balance {
  52. fmt.Println("余额不足..")
  53. break
  54. } else {
  55. balance -= money
  56. }
  57. fmt.Println("本次支出说明:")
  58. fmt.Scanln(&note)
  59. //将这个支出情况,拼接到 details 变量
  60. details += fmt.Sprintf("\n支出\t\t%v\t\t%v\t\t%v", balance, money, note)
  61. flags = true
  62. case "4":
  63. fmt.Println("你确定要退出吗?y/n")
  64. choice := ""
  65. for {
  66. fmt.Scanln(&choice)
  67. if choice == "y" || choice == "n" {
  68. break
  69. }
  70. fmt.Println("你的输入有误,请重新输入 y/n")
  71. }
  72. if choice == "y" {
  73. loop = false
  74. }
  75. default:
  76. fmt.Println("请输入正确选项..")
  77. }
  78. if !loop {
  79. break
  80. }
  81. }
  82. fmt.Println("你退出家庭记账软件的使用..")
  83. }
  1. 将面向过程的代码修改成面向对象的方法,编写 myFamilyAccount.go,并使用 testMyFamilyAccount.go 去完成测试。
    • 思路分析:
      • 把记账软件的功能,封装到一个结构体中,然后调用该结构体的方法,来实现记账,显示明细。结构体的名字:FamilyAccount
      • 在通过在 main 方法中,创建一个结构体 FamilyAccount 实例,实现记账即可。
      • 代码并不需要重写,只需要重新组织即可。 ```go //-utils包:familyAccount.go package utils

import “fmt”

type FamilyAccount struct { //声明必要的字段 //声明一个字段,保存接收用户输入的选项 key string //声明一个字段,控制是否退出 for loop bool //定义账户的余额 balance float64 //每次收支的金额 money float64 //每次收支的说明 note string //定义一个字段,记录是否有收支行为 flag bool //收支的详情使用字符串来记录 //当有收支时,只需要对 details 拼接处理即可 details string }

//编写一个工厂模式的构造方法,返回一个 FamilyAccount 实例 func NewFamilyAccount() FamilyAccount { return &FamilyAccount{ key : “”, loop : true, balance : 10000.0, money : 0.0, note : “”, flag : false, details : “收支\t\t账户余额\t\t收支金额\t\t说明”,

  1. }

}

//给该结构体绑定相应的方法 //将显示明细写成一个方法 func (this *FamilyAccount) showDetails() { fmt.Println(“——————当前收支明细记录——————“) if this.flag { fmt.Println(this.details) } else { fmt.Println(“当前没有收支明细…来一笔吧!”) } }

//给该结构体绑定相应的方法 //将登记收入写成一个方法 func (this *FamilyAccount) income() { fmt.Println(“本次收入金额:”) fmt.Scanln(&this.money) this.balance += this.money //修改账户余额 fmt.Println(“本次收入说明:”) fmt.Scanln(&this.note) //将这个收入情况,拼接到 details 变量 this.details += fmt.Sprintf(“\n收入\t\t%v\t\t%v\t\t%v”, this.balance, this.money, this.note) this.flag = true }

//给该结构体绑定相应的方法 //将登记支出写成一个方法 func (this *FamilyAccount) pay() { fmt.Println(“本次支出金额:”) fmt.Scanln(&this.money) //这里需要做必要的判断 if this.money > this.balance { fmt.Println(“余额不足..”) //break } else { this.balance -= this.money } fmt.Println(“本次支出说明:”) fmt.Scanln(&this.note) //将这个支出情况,拼接到 details 变量 this.details += fmt.Sprintf(“\n支出\t\t%v\t\t%v\t\t%v”, this.balance, this.money, this.note) this.flag = true }

//给该结构体绑定相应的方法 //将退出系统写成一个方法 func (this *FamilyAccount) exit() { fmt.Println(“你确定要退出吗?y/n”) choice := “” for { fmt.Scanln(&choice) if choice == “y” || choice == “n” { break } fmt.Println(“你的输入有误,请重新输入 y/n”) } if choice == “y” { this.loop = false } }

//给该结构体绑定相应的方法 //显示主菜单 func (this *FamilyAccount) MainMenu() { for { fmt.Println(“\n——————家庭收支记账软件——————“) fmt.Println(“ 1 收支明细”) fmt.Println(“ 2 登记收入”) fmt.Println(“ 3 登记支出”) fmt.Println(“ 4 退出软件”) fmt.Print(“请选择(1-4): “)

  1. fmt.Scanln(&this.key)
  2. switch this.key {
  3. case "1":
  4. this.showDetails()
  5. case "2":
  6. this.income()
  7. case "3":
  8. this.pay()
  9. case "4":
  10. this.exit()
  11. default:
  12. fmt.Println("请输入正确选项..")
  13. }
  14. if !this.loop {
  15. break
  16. }
  17. }
  18. fmt.Println("你退出家庭记账软件的使用..")

}

  1. ```go
  2. //-main包-main.go
  3. package main
  4. import (
  5. "GoProject/src/go_code/chapter12/project_case_02/utils"
  6. "fmt"
  7. )
  8. func main() {
  9. fmt.Println("这个是面向对象的方式完成~")
  10. utils.NewFamilyAccount().MainMenu() //思路清晰
  11. }

课程来源