上场考试,根据思路进行了面向过程编写,本篇引导为:面向对象编写
还记得对象是由什么组成的吗?属性,方法
一、需求讨论
实现一个“控制台版家庭收支记账软件”的业务核心逻辑,用结构体封装账户数据和操作方法,支持循环显示菜单,让用户可以反复进行:
- 查看收支明细
- 登记收入
- 登记支出
- 退出软件(带二次确认)
1. 菜单
使用 for { … } 无限循环,并根据退出变量进行中断循环。
每轮循环打印菜单:
- 收支明细
- 登记收入
- 登记支出
- 退出软件
2. 登记收入
记录一次收入操作,并更新余额与明细。
3. 登记支出
记录一次支出操作,并更新余额与明细,且要校验余额是否足够。
4. 退出软件
让用户确认是否退出主菜单循环(包含二次确认)。
二、面向对象
1. 封装属性
根据需求我们确定一些属性,并进行封装到结构体中
// MyFamilyAccountingTest 创建结构体 声明属性
type MyFamilyAccountingTest struct {
// 输入选项值
key string
// 是否退出
loop bool
// 定义账户余额
balance float64
// 定义收支金额
money float64
// 描述
note string
// 收支详情
details string
// 确定要退出吗
choice string
// 收支行为
flag bool
}
并根据这些属性进行工厂模式,初始化属性,并返回对象指针
// NewMyFamilyAccountingTest 通过工厂模式,进行初始化结构体属性
func NewMyFamilyAccountingTest() *MyFamilyAccountingTest {
return &MyFamilyAccountingTest{
key: "",
loop: false,
balance: 10000.0,
money: 0.0,
note: "",
details: "收支\t账户金额\t收支金额\t说 明",
choice: "",
flag: false,
}
}
2. 菜单方法
进行绑定菜单方法到家庭账户结构体上,方法功能为用户提供选项,并获取选项,进行跳转到对应的功能
// ShowMenu 菜单
func (this *MyFamilyAccountingTest) ShowMenu() {
// 一个程序不可能只用一次,进行多次,所以使用for循环
for {
fmt.Println("---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记支出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
fmt.Scanln(&this.key)
switch this.key {
case "1":
this.ShowDetails()
case "2":
this.Income()
case "3":
this.Pay()
case "4":
this.Outcome()
default:
fmt.Println("请输入正确选项")
}
// 如果退出,则结束循环
if this.loop {
break
}
}
}
3. 收支明细
根据菜单定义的方法,进行编写收支明细
// ShowDetails 显示收支明细
func (this *MyFamilyAccountingTest) ShowDetails() {
if this.flag {
fmt.Println("-----------当前收支明细记录-----------")
fmt.Println(this.details)
} else {
fmt.Println("当前没有收支明细")
}
}
4. 登记收入
获取用户的信息,并更新到变量中
// Income 收支
func (this *MyFamilyAccountingTest) Income() {
fmt.Println("本次收入金额:")
fmt.Scanln(&this.money)
this.balance += this.money
fmt.Println("本次收入说明:")
fmt.Scanln(&this.note)
this.details += fmt.Sprintf("\n收入\t%v\t%v\t%v", this.balance, this.money, this.note)
this.flag = true
}
5. 登记支出
获取用户,进行判断支出金额是否超出余额,并信息更新变量
// Pay 支出
func (this *MyFamilyAccountingTest) Pay() {
fmt.Println("本次支出金额:")
fmt.Scanln(&this.money)
// 判断支出是否超出
if this.money > this.balance {
fmt.Println("余额不足")
return
}
this.balance -= this.money
fmt.Println("本次支出说明:")
fmt.Scanln(&this.note)
this.details += fmt.Sprintf("\n支出\t%v\t%v\t%v", this.balance, this.money, this.note)
this.flag = true
}
6. 退出
引导用户进行二次确认,并跳出循环
// Outcome 退出
func (this *MyFamilyAccountingTest) Outcome() {
fmt.Println("你确定要退出吗?y/n")
for {
fmt.Scanln(&this.choice)
if this.choice == "y" || this.choice == "n" {
break
}
fmt.Println("你的输入有误,你重新输入 y/n")
}
if this.choice == "y" {
this.loop = true
}
}
没有细致划分对象,这里只是单纯的使用了家庭账户余额结构体
附
common包下,MyFamilyAccountingTest结构体
package common
import "fmt"
// MyFamilyAccountingTest 创建结构体 声明属性
type MyFamilyAccountingTest struct {
// 输入选项值
key string
// 是否退出
loop bool
// 定义账户余额
balance float64
// 定义收支金额
money float64
// 描述
note string
// 收支详情
details string
// 确定要退出吗
choice string
// 收支行为
flag bool
}
// NewMyFamilyAccountingTestTest 通过工厂模式,进行初始化结构体属性
func NewMyFamilyAccountingTest() *MyFamilyAccountingTest {
return &MyFamilyAccountingTest{
key: "",
loop: false,
balance: 10000.0,
money: 0.0,
note: "",
details: "收支\t账户金额\t收支金额\t说 明",
choice: "",
flag: false,
}
}
// ShowMenu 菜单
func (this *MyFamilyAccountingTest) ShowMenu() {
// 一个程序不可能只用一次,进行多次,所以使用for循环
for {
fmt.Println("---------------------家庭收支记账软件---------------------")
fmt.Println(" 1 收支明细")
fmt.Println(" 2 登记收入")
fmt.Println(" 3 登记支出")
fmt.Println(" 4 退出软件")
fmt.Print("请选择(1-4):")
fmt.Scanln(&this.key)
switch this.key {
case "1":
this.ShowDetails()
case "2":
this.Income()
case "3":
this.Pay()
case "4":
this.Outcome()
default:
fmt.Println("请输入正确选项")
}
// 如果退出,则结束循环
if this.loop {
break
}
}
}
// ShowDetails 显示收支明细
func (this *MyFamilyAccountingTest) ShowDetails() {
if this.flag {
fmt.Println("-----------当前收支明细记录-----------")
fmt.Println(this.details)
} else {
fmt.Println("当前没有收支明细")
}
}
// Income 收支
func (this *MyFamilyAccountingTest) Income() {
fmt.Println("本次收入金额:")
fmt.Scanln(&this.money)
this.balance += this.money
fmt.Println("本次收入说明:")
fmt.Scanln(&this.note)
this.details += fmt.Sprintf("\n收入\t%v\t%v\t%v", this.balance, this.money, this.note)
this.flag = true
}
// Pay 支出
func (this *MyFamilyAccountingTest) Pay() {
fmt.Println("本次支出金额:")
fmt.Scanln(&this.money)
// 判断支出是否超出
if this.money > this.balance {
fmt.Println("余额不足")
return
}
this.balance -= this.money
fmt.Println("本次支出说明:")
fmt.Scanln(&this.note)
this.details += fmt.Sprintf("\n支出\t%v\t%v\t%v", this.balance, this.money, this.note)
this.flag = true
}
// Outcome 退出
func (this *MyFamilyAccountingTest) Outcome() {
fmt.Println("你确定要退出吗?y/n")
for {
fmt.Scanln(&this.choice)
if this.choice == "y" || this.choice == "n" {
break
}
fmt.Println("你的输入有误,你重新输入 y/n")
}
if this.choice == "y" {
this.loop = true
}
}
测试程序入库MyFamilyAccountingDemo
package main
import "learn_golang_project/src/go_code/common"
func main() {
common.NewMyFamilyAccountingTest().ShowMenu()
}

被折叠的 条评论
为什么被折叠?



