Go项目-家庭收支记账软件
Go项目-家庭收支记账软件
项目开发流程
项目需求说明
- 模拟实现基于文本界面的《家庭记账软件》
- 软件能够记录家庭的收入、支出,并能够打印收支明细表
项目代码编写
主菜单的设计
func main() {
// 声明一个变量保存用户的输入
key := ""
// 声明一个变量,控制是否退出for循环
loop := true
// 显示主菜单
for loop {
fmt.Println("---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记输出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
// 接收用户的输入
fmt.Scanln(&key)
// 对用户的输入进行判断
switch key {
case "1":
fmt.Println("---------------------当前收支明细记录---------------------")
case "2":
case "3":
fmt.Println("登记支出------")
case "4":
loop = false
default:
fmt.Println("请输入正确的选项------")
}
}
fmt.Println("-------------------退出家庭收支记账软件-------------------")
}
没啥有意思的,基础编程,效果如下:
显示明细与登记输入
case "1":
fmt.Println("---------------------当前收支明细记录---------------------")
fmt.Println(details)
case "2":
fmt.Println("-------------------------登记收入-------------------------")
fmt.Print("本次收入金额:")
fmt.Scanln(&money)
fmt.Print("本次收入说明:")
fmt.Scanln(¬e)
balance += money
details += fmt.Sprintf("收 入\t%v\t%v\t%v\n", balance, money, note)
fmt.Println("收入登记成功!")
其中明细是用字符串拼接实现的,实际中应该是要操作数据库的
登记支出
case "3":
fmt.Println("-------------------------登记支出-------------------------")
fmt.Print("本次支出金额:")
fmt.Scanln(&money)
if money > balance {
fmt.Println("余额的金额不足!")
break
} else if money <= 0 {
fmt.Println("支出金额应为正数!")
}
fmt.Print("本次支出说明:")
fmt.Scanln(¬e)
balance -= money
details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", balance+money, money, balance, note)
fmt.Println("支出登记成功!")
注意支出的金额要小于账户余额,也要注意收入和支出的时候用户输入的数字需要为正数。
完善代码
退出时增加确认条件
case "4":
var choice byte
for {
fmt.Print("确定退出?(y/n):")
fmt.Scanf("%c\n", &choice)
if choice == 'y' {
loop = false
break
} else if choice == 'n' {
break
} else {
fmt.Println("输入有误!!请重新输入")
}
}
注意scanf字符的时候与C语言是差不多的,需要考虑回车符号
没有记录时不输出收支详情字符串
// 判断当前是否有输入或者输出的记录
flag := false
也没啥好说的,加个标志位,有记录的时候将这个标志位改掉就可以了
面向对象
将上面的面向过程的代码修改成面向对象的代码
主要思想:将记账软件的功能封装到结构体中,然后调用这个结构体的方法完成功能。
定义结构体
// 定义结构体
type FamilyAccount struct {
// 声明一个变量保存用户的输入
key string
// 声明一个变量,控制是否退出for循环
loop bool
// 定义账户的初始值
balance float64
// 定义每次收支的金额和说明
money float64
note string
// 收支的详情使用字符串来记录
// 当有记录时对这个字符串进行拼接
details string
// 判断当前是否有输入或者输出的记录
flag bool
}
注意定义结构体的时候不能进行初始化
工厂模式返回结构体的指针
// 编写一个工厂模式的构造方法,返回结构体的指针
func NewFamilyAcount() *FamilyAccount {
return &FamilyAccount{
key: "",
loop: true,
balance: 10000.0,
money: 0.0,
note: "",
details: "收 支\t收支前账户余额\t收支金额\t收支后账户余额\t说 明\n",
flag: false,
}
}
注意如果结构体是私有的是一定要有的,公开的也可以有,以后就要记得一定要有这样的一个方法
编写各种方法
简单改造一下面向过程的代码即可完成面向对象的效果
将显示明细写成一个方法
func (fa *FamilyAccount) showDetails() {
if !fa.flag {
fmt.Println("当前没有任何收支记录!")
} else {
fmt.Println("---------------------当前收支明细记录---------------------")
fmt.Println(fa.details)
}
}
将登记收入写成一个方法
func (fa *FamilyAccount) income() {
fmt.Println("-------------------------登记收入-------------------------")
fmt.Print("本次收入金额:")
fmt.Scanln(&fa.money)
// 收入金额不能是负数
if fa.money <= 0 {
fmt.Println("收入金额应为正数!")
return
}
fmt.Print("本次收入说明:")
fmt.Scanln(&fa.note)
fa.balance += fa.money
fa.details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", fa.balance-fa.money, fa.money, fa.balance, fa.note)
fmt.Println("收入登记成功!")
fa.flag = true
}
将登记支出写成一个方法
func (fa *FamilyAccount) pay() {
fmt.Println("-------------------------登记支出-------------------------")
fmt.Print("本次支出金额:")
fmt.Scanln(&fa.money)
if fa.money > fa.balance {
fmt.Println("余额的金额不足!")
return
} else if fa.money <= 0 {
fmt.Println("支出金额应为正数!")
}
fmt.Print("本次支出说明:")
fmt.Scanln(&fa.note)
fa.balance -= fa.money
fa.details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", fa.balance+fa.money, fa.money, fa.balance, fa.note)
fmt.Println("支出登记成功!")
fa.flag = true
}
将退出系统写成一个方法
func (fa *FamilyAccount) exit() {
var choice byte
for {
fmt.Print("确定退出?(y/n):")
fmt.Scanf("%c\n", &choice)
if choice == 'y' {
fa.loop = false
break
} else if choice == 'n' {
break
} else {
fmt.Println("输入有误!!请重新输入")
}
}
}
显示主菜单
func (fa *FamilyAccount) MainMenu() {
// 显示主菜单
for fa.loop {
fmt.Println("\n---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记输出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
// 接收用户的输入
fmt.Scanln(&fa.key)
// 对用户的输入进行判断
switch fa.key {
case "1":
fa.showDetails()
case "2":
fa.income()
case "3":
fa.pay()
case "4":
fa.exit()
default:
fmt.Println("请输入正确的选项------")
}
}
}
主函数中进行调用
func main() {
utils.NewFamilyAcount().MainMenu()
}
增加扩展功能
添加一个用户登录的功能,即只有将用户名和密码输入正确后才能打开软件,否则无法看到主界面
实现:在显示菜单之前增加一个无限循环要求用户输入用户名和密码,只有输入正确才能退出循环
for {
var username, password string
fmt.Print("请输入用户名:")
fmt.Scanln(&username)
fmt.Print("请输入密码:")
fmt.Scanln(&password)
if fa.login(username, password) {
break
} else {
fmt.Println("用户名或密码错误!")
}
}
用户登录的方法
func (fa *FamilyAccount) login(username string, password string) bool {
if (username == fa.username) && (password == fa.password) {
return true
}
return false
}
完整源代码
面向过程的代码
package main
import "fmt"
func main() {
// 声明一个变量保存用户的输入
key := ""
// 声明一个变量,控制是否退出for循环
loop := true
// 定义账户的初始值
balance := 10000.0
// 定义每次收支的金额和说明
var money float64
var note string
// 收支的详情使用字符串来记录
// 当有记录时对这个字符串进行拼接
details := "收 支\t收支前账户余额\t收支金额\t收支后账户余额\t说 明\n"
// 判断当前是否有输入或者输出的记录
flag := false
// 显示主菜单
for loop {
fmt.Println("\n---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记输出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
// 接收用户的输入
fmt.Scanln(&key)
// 对用户的输入进行判断
switch key {
case "1":
if !flag {
fmt.Println("当前没有任何收支记录!")
} else {
fmt.Println("---------------------当前收支明细记录---------------------")
fmt.Println(details)
}
case "2":
fmt.Println("-------------------------登记收入-------------------------")
fmt.Print("本次收入金额:")
fmt.Scanln(&money)
// 收入金额不能是负数
if money <= 0 {
fmt.Println("收入金额应为正数!")
break
}
fmt.Print("本次收入说明:")
fmt.Scanln(¬e)
balance += money
details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", balance-money, money, balance, note)
fmt.Println("收入登记成功!")
flag = true
case "3":
fmt.Println("-------------------------登记支出-------------------------")
fmt.Print("本次支出金额:")
fmt.Scanln(&money)
if money > balance {
fmt.Println("余额的金额不足!")
break
} else if money <= 0 {
fmt.Println("支出金额应为正数!")
}
fmt.Print("本次支出说明:")
fmt.Scanln(¬e)
balance -= money
details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", balance+money, money, balance, note)
fmt.Println("支出登记成功!")
flag = true
case "4":
var choice byte
for {
fmt.Print("确定退出?(y/n):")
fmt.Scanf("%c\n", &choice)
if choice == 'y' {
loop = false
break
} else if choice == 'n' {
break
} else {
fmt.Println("输入有误!!请重新输入")
}
}
default:
fmt.Println("请输入正确的选项------")
}
}
fmt.Println("-------------------退出家庭收支记账软件-------------------")
}
面向对象的代码
.
├── Family-Ledger
│ ├── main
│ │ └── main.go
│ └── utils
│ └── familyAccount.go
main.go
package main
import (
"Go-Projects/Family-Ledger/utils"
)
func main() {
utils.NewFamilyAcount().MainMenu()
}
familyAccount.go
package utils
import "fmt"
// 定义结构体
type FamilyAccount struct {
// 用户名和密码
username string
password string
// 声明一个变量保存用户的输入
key string
// 声明一个变量,控制是否退出for循环
loop bool
// 定义账户的初始值
balance float64
// 定义每次收支的金额和说明
money float64
note string
// 收支的详情使用字符串来记录
// 当有记录时对这个字符串进行拼接
details string
// 判断当前是否有输入或者输出的记录
flag bool
}
// 编写一个工厂模式的构造方法,返回结构体的指针
func NewFamilyAcount() *FamilyAccount {
return &FamilyAccount{
username: "admin",
password: "password",
key: "",
loop: true,
balance: 10000.0,
money: 0.0,
note: "",
details: "收 支\t收支前账户余额\t收支金额\t收支后账户余额\t说 明\n",
flag: false,
}
}
// 给结构体绑定相应的方法
// 将显示明细写成一个方法
func (fa *FamilyAccount) showDetails() {
if !fa.flag {
fmt.Println("当前没有任何收支记录!")
} else {
fmt.Println("---------------------当前收支明细记录---------------------")
fmt.Println(fa.details)
}
}
// 将登记收入写成一个方法
func (fa *FamilyAccount) income() {
fmt.Println("-------------------------登记收入-------------------------")
fmt.Print("本次收入金额:")
fmt.Scanln(&fa.money)
// 收入金额不能是负数
if fa.money <= 0 {
fmt.Println("收入金额应为正数!")
return
}
fmt.Print("本次收入说明:")
fmt.Scanln(&fa.note)
fa.balance += fa.money
fa.details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", fa.balance-fa.money, fa.money, fa.balance, fa.note)
fmt.Println("收入登记成功!")
fa.flag = true
}
// 将登记支出写成一个方法
func (fa *FamilyAccount) pay() {
fmt.Println("-------------------------登记支出-------------------------")
fmt.Print("本次支出金额:")
fmt.Scanln(&fa.money)
if fa.money > fa.balance {
fmt.Println("余额的金额不足!")
return
} else if fa.money <= 0 {
fmt.Println("支出金额应为正数!")
}
fmt.Print("本次支出说明:")
fmt.Scanln(&fa.note)
fa.balance -= fa.money
fa.details += fmt.Sprintf("收 入\t%v\t%v\t%v\t%v\n", fa.balance+fa.money, fa.money, fa.balance, fa.note)
fmt.Println("支出登记成功!")
fa.flag = true
}
// 将退出系统写成一个方法
func (fa *FamilyAccount) exit() {
var choice byte
for {
fmt.Print("确定退出?(y/n):")
fmt.Scanf("%c\n", &choice)
if choice == 'y' {
fa.loop = false
break
} else if choice == 'n' {
break
} else {
fmt.Println("输入有误!!请重新输入")
}
}
}
// 用户登录的功能
func (fa *FamilyAccount) login(username string, password string) bool {
if (username == fa.username) && (password == fa.password) {
return true
}
return false
}
// 显示主菜单
func (fa *FamilyAccount) MainMenu() {
for {
var username, password string
fmt.Print("请输入用户名:")
fmt.Scanln(&username)
fmt.Print("请输入密码:")
fmt.Scanln(&password)
if fa.login(username, password) {
break
} else {
fmt.Println("用户名或密码错误!")
}
}
// 显示主菜单
for fa.loop {
fmt.Println("\n---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记输出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
// 接收用户的输入
fmt.Scanln(&fa.key)
// 对用户的输入进行判断
switch fa.key {
case "1":
fa.showDetails()
case "2":
fa.income()
case "3":
fa.pay()
case "4":
fa.exit()
default:
fmt.Println("请输入正确的选项------")
}
}
}
Go项目-家庭收支记账软件
https://zhangzhao219.github.io/2022/11/02/Go/Go-Project-Family-Ledger/