首页 > 编程学习 > [go学习笔记.第十一章.项目案例] 1.家庭收支记账软件项目

一.基本介绍

1.项目开发流程说明

2.项目需求说明

目标:

模拟实现一个基于文本界面的<<家庭记账软件>>

掌握初步的编程技巧和调试技巧

主要涉及以下知识点 :

(1).局部变量和基本数据类型

(2).循环语句

(3).分支语句

(4).简单的屏幕输出格式控制

(5).进阶:面向对象编程使用

需求说明

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

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

项目采用分级菜单方式,主菜单如下:

3.项目界面

(1).收支明细界面

(2).登记收入界面 

(3).登记支出界面 

 (4).退出界面

二.代码实现

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

功能1:   

        先完成可以显示主菜单,并且可以退出

思路分析: 

        显示给出的主界面,主菜单的显示,当用户输入 4 时,就退出该程序

功能2:

        完成可以显示明细和登记收入的功能

思路分析:

        (1).因为需要显示明细,我们定义一个变量details来记录

        (2).还需要定义变量来记录余额(balance)、每次收支的金额(money),每次收支的说明(note)

功能 3:

        完成登记支出的功能

思路分析:

        登记支出的功能和登录收入的功能类似,做些修改即可

功能1:   先完成可以显示主菜单,并且可以退出

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.Println("请选择(1~4):")
        fmt.Scanln(&key)

        switch key {
        case "1":
            fmt.Println("----------------当前收支明细------------------")
        case "2":
        case "3":
            fmt.Println("登记支出")
        case "4":
            loop = false
        default :
            fmt.Println("请输入正确的选项")       
        }

        if !loop {
            break
        }
    }

    fmt.Println("你退出了家庭收支记账软件的使用")
}

功能2: 完成可以显示明细和登记收入的功能

package main

import (
    "fmt"
)

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

        switch key {
        case "1":
            fmt.Println("----------------当前收支明细------------------")
            fmt.Println(details)
        case "2":
            fmt.Println("本次收入金额:")
            fmt.Scanln(&money)
            balance += money    //修改账户余额
            fmt.Println("本次收入说明:")
            fmt.Scanln(&note)
            //将这个收入情况,拼接到details变量
            //收入 11000 1000 有人发红包
            details += fmt.Sprintf("\n收入\t%v\t\t%v\t\t%v",balance, money, note)

        case "3":
            fmt.Println("登记支出")
        case "4":
            loop = false
        default :
            fmt.Println("请输入正确的选项") 
        }

        if !loop {
            break
        }
    }

    fmt.Println("你退出了家庭收支记账软件的使用")
}

功能 3:  完成登记支出的功能

package main

import (
    "fmt"
)

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

        switch key {
        case "1":
            fmt.Println("----------------当前收支明细------------------")
            fmt.Println(details)
        case "2":
            fmt.Println("本次收入金额:")
            fmt.Scanln(&money)
            balance += money    //修改账户余额
            fmt.Println("本次收入说明:")
            fmt.Scanln(&note)
            //将这个收入情况,拼接到details变量
            //收入 11000 1000 有人发红包
            details += fmt.Sprintf("\n收入\t%v\t\t%v\t\t%v",balance, money, note)
        case "3":
            fmt.Println("本次支出金额:")
            fmt.Scanln(&money)
            //这里需要做一个判断
            if money > balance {
                fmt.Println("支出的余额不足")
                break
            }
            balance -= money    //修改账户余额
            fmt.Println("本次支出说明:")
            fmt.Scanln(&note)
            //将这个支出情况,拼接到details变量
            //支出 11000 1000 吃中午饭
            details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v",balance, money, note)
        case "4":
            loop = false
        default :
            fmt.Println("请输入正确的选项")  
        }

        if !loop {
            break
        }
    }

    fmt.Println("你退出了家庭收支记账软件的使用")
}

2.项目代码改进

(1).用户输入 4 退出时,给出提示”你确定要退出吗? y / n " ,必须输入正确的 y / n 指令,否则循环输入,直到输入 y 或者 n 

(2).当没有任何收支明细时,提示”当前没有收支明细 … 来一笔吧!"

(3).在支出时,判断余额是否够,并给出相应的提示

package main

import (
    "fmt"
)

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

        switch key {
        case "1":
            fmt.Println("----------------当前收支明细------------------")
            if flag {
                fmt.Println(details)
            } else {
                fmt.Println("当前没有收支明细,来一笔")
            }
        case "2":
            fmt.Println("本次收入金额:")
            fmt.Scanln(&money)
            balance += money    //修改账户余额
            fmt.Println("本次收入说明:")
            fmt.Scanln(&note)
            //将这个收入情况,拼接到details变量
            //收入 11000 1000 有人发红包
            details += fmt.Sprintf("\n收入\t%v\t\t%v\t\t%v",balance, money, note)
            flag = true
        case "3":
            fmt.Println("本次支出金额:")
            fmt.Scanln(&money)
            //这里需要做一个判断
            if money > balance {
                fmt.Println("支出的余额不足")
                break
            }
            balance -= money    //修改账户余额
            fmt.Println("本次支出说明:")
            fmt.Scanln(&note)
            //将这个支出情况,拼接到details变量
            //支出 11000 1000 吃中午饭
            details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v",balance, money, note)
            flag = true
        case "4":
            fmt.Println("你确定要退出吗? y/n")
            choice := ""
            for {
                fmt.Scanln(&choice)
                if choice == "y" || choice == "n" {
                    break
                }
                fmt.Println("你输入有误,请重新输入 y/n")  
            }
            if choice == "y" {
                loop = false
            }
        
        default :
            fmt.Println("请输入正确的选项")
        }

        if !loop {
            break
        }
    }

    fmt.Println("你退出了家庭收支记账软件的使用")
}

(4).将面向过程的代码修改成面向对象的方法,编写myFamilyAccount.go,并使用 testMyFamilyAccount.go 去完测试

思路分析:

        把记账软件的功能,封装到一个结构体中,然后调用该结构体的方法,来实现记账,显示明细。结构体的名字 FamilyAccount,在通过main方法中,创建一个结构体FamilyAccount实例,实现记账即可,码不需要重写,只需要重写组织一下

myFamilyAccount.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 : "",
        details : "收支\t账号余额\t收支金额\t说    明",
    }
}
//将显示明细写成一个方法
func (this *FamilyAccount) showDetails() {
    fmt.Println("----------------当前收支明细------------------")
    if this.flag {
        fmt.Println(this.details)
    } else {
        fmt.Println("当前没有收支明细,来一笔")
    }
}

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

//将登记支出写成一个方法,绑定到*FamilyAccount结构体
func (this *FamilyAccount) pay()  {
    fmt.Println("本次支出金额:")
    fmt.Scanln(&this.money)
    //这里需要做一个判断
    if this.money > this.balance {
        fmt.Println("支出的余额不足")
    }
    this.balance -= this.money  //修改账户余额
    fmt.Println("本次支出说明:")
    fmt.Scanln(&this.note)
    //将这个支出情况,拼接到details变量
    //支出 11000 1000 吃中午饭
    this.details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v", this.balance, this.money, this.note)
    this.flag = true
}

//将退出写成一个方法,绑定到*FamilyAccount结构体
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.Println("请选择(1~4):")
        fmt.Scanln(&this.key)

        switch this.key {
        case "1":
            this.showDetails()
        case "2":
            this.income()
        case "3":
            this.pay()
        case "4":
            this.exit()
        default :
            fmt.Println("请输入正确的选项") 
        }

        if !this.loop {
            break
        }
    }
    fmt.Println("你退出了家庭收支记账软件的使用")
}

main.go

package main

import (
    "fmt"
    "go_code/familyAccount/utils"
)

func main() {
    fmt.Println("面向对象方式实现")
    utils.NewFamilyAccount().MainMenu()
}

对项目的扩展功能:

        1.对上面的项目完成一个转账功能

        2.使用该软件前,有一个登录功能,只有输入正确的用户名,密码才能操作

 myFamilyAccount.go

package utils

import (
    "fmt"
)

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

    //定义用户名
    name string
    //定义用户密码
    pwd string
} 

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

//将显示明细写成一个方法
func (this *FamilyAccount) showDetails() {
    fmt.Println("----------------当前收支明细------------------")
    if this.flag {
        fmt.Println(this.details)
    } else {
        fmt.Println("当前没有收支明细,来一笔")
    }
}

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

//将登记支出写成一个方法,绑定到*FamilyAccount结构体
func (this *FamilyAccount) pay()  {
    fmt.Println("本次支出金额:")
    fmt.Scanln(&this.money)
    //这里需要做一个判断
    if this.money > this.balance {
        fmt.Println("支出的余额不足")
    }
    this.balance -= this.money  //修改账户余额
    fmt.Println("本次支出说明:")
    fmt.Scanln(&this.note)
    //将这个支出情况,拼接到details变量
    //支出 11000 1000 吃中午饭
    this.details += fmt.Sprintf("\n支出\t%v\t\t%v\t\t%v", this.balance, this.money, this.note)
    this.flag = true
}

//将退出写成一个方法,绑定到*FamilyAccount结构体
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
    }
}

//将判断用户登录写成一个方法,绑定到*FamilyAccount结构体
func (this *FamilyAccount) login() {
    for {
        fmt.Println("请输入用户名:")
        fmt.Scanln(&this.name)
        fmt.Println("请输入密码:")
        fmt.Scanln(&this.pwd)
        if this.name == "root" && this.pwd == "123456" {
            break 
        }
        fmt.Println("用户名或密码错误,请重新输入")
    }
}

//给结构体绑定方法
//显示主菜单
func (this *FamilyAccount) MainMenu() {
    this.login() 
    for {
        fmt.Println("\n----------------家庭收支记账软件------------------")
        fmt.Println("                1.收支明细")
        fmt.Println("                2.登记收入")
        fmt.Println("                3.登记支出")
        fmt.Println("                4.退出软件")
        fmt.Println("请选择(1~4):")
        fmt.Scanln(&this.key)

        switch this.key {
        case "1":
            this.showDetails()
        case "2":
            this.income()
        case "3":
            this.pay()
        case "4":
            this.exit()
        default :
            fmt.Println("请输入正确的选项")    
        }

        if !this.loop {
            break
        }
    }
    fmt.Println("你退出了家庭收支记账软件的使用")
}

[上一节]go学习笔记.第十章.面向对象编程] 12.类型断言引出和基本使用

[下一节][go学习笔记.第十一章.项目案例] 2.客户信息管理系统 

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式