第十二章 Golang家庭收支记账软件项目

简介: 第十二章 Golang家庭收支记账软件项目

1.项目开发流程

2.项目需求说明

  1. 模拟实现基于文本界面的《家庭记账软件》
  2. 该软件能够记录家庭的收入,支出,并能够打印收支明细表

3.项目的界面

4.项目代码实现

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

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

思路分析:

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

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

思路分析:

  1. 因为需要显示明细,我们定义一个变量details string 来记录
  2. 还需要定义变量来记录余额(balance),每次收支的金额(money),每次收支的说明(note)

代码改进

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

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("-------家庭收支记账软件---------")
    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("\n----------当前收支明细记录-----------")
        if flag {
          fmt.Println(details)
        }else{
          fmt.Println("当前没有收支明细...  来一笔吧!")
        }
        // fmt.Println(details)
      case "2":
        fmt.Println("本次收入金额:")
        fmt.Scanln(&money)
        balance += money // 修改账户余额
        fmt.Println("本次收入说明:")
        fmt.Scanln(&note)
        // 将这个收入情况,拼接到details变量
        details += fmt.Sprintf("\n收入\t%v\t%v\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 += fmt.Sprintf("\n支出\t%v\t%v\t%v",balance,money,note)
      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 {
      fmt.Println("你退出家庭账本")
      break;
    }
    
    
  }
  
}

将上面的代码改成面向对象的方法,编写myFamilyAccount.go,并使用testMyFamilyAccount.go去完成测试

思路分析

把记账软件的功能,封装到一个结构体中,然后调用该结构体的方法,来实现记账,显示明细。结构体的名字FamilyAccount

在通过main方法中,创建一个结构体FamilyAccount实例,实现记账即可。

// 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说  明"
  }
}
// 显示明细方法
func (this *FamilyAccount) showDetails(){
  fmt.Println("\n----------当前收支明细记录-----------")
  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%v\t%v\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
  }
  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)
}
// 退出方法
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("-------家庭收支记账软件---------")
    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;
    }
    
    
  }
  
}

// main.go

package main 
import (
  "go_code/familyaccount/utils"
)
func main(){
  
  fmt.Println("这个是面向对象的方式完成~~")
  utils.NewFamilyAccount().MainMenu() 
}

感谢大家观看,我们下次见

目录
相关文章
|
5月前
|
传感器 数据采集 物联网
Golang硬件控制:将软件力量扩展到物理世界
Golang硬件控制:将软件力量扩展到物理世界
|
9月前
|
Kubernetes JavaScript 前端开发
为什么 Golang 正在接管软件行业
为什么 Golang 正在接管软件行业
|
6月前
|
存储 编译器 Go
Golang 语言的多种变量声明方式和使用场景
Golang 语言的多种变量声明方式和使用场景
32 0
|
6月前
|
缓存 编译器 Go
Golang 语言 vendor 在 GOPATH 和 Modules 中的区别
Golang 语言 vendor 在 GOPATH 和 Modules 中的区别
31 0
|
6月前
|
Go 数据中心 微服务
Golang 语言微服务的服务发现组件 Consul 的系统架构介绍
Golang 语言微服务的服务发现组件 Consul 的系统架构介绍
59 0
|
1月前
|
SQL 前端开发 Go
编程笔记 GOLANG基础 001 为什么要学习Go语言
编程笔记 GOLANG基础 001 为什么要学习Go语言
|
6月前
|
存储 JSON Go
Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?
Golang 语言 gRPC 服务怎么同时支持 gRPC 和 HTTP 客户端调用?
76 0
|
6月前
|
存储 安全 Go
Golang 语言微服务的服务注册与发现组件 Consul
Golang 语言微服务的服务注册与发现组件 Consul
57 0
|
3月前
|
物联网 Go 网络性能优化
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式
使用Go语言(Golang)可以实现MQTT协议的点对点(P2P)消息发送。MQTT协议本身支持多种消息收发模式【1月更文挑战第21天】【1月更文挑战第104篇】
101 1
|
1天前
|
安全 Go 开发者
Golang深入浅出之-Go语言并发编程面试:Goroutine简介与创建
【4月更文挑战第22天】Go语言的Goroutine是其并发模型的核心,是一种轻量级线程,能低成本创建和销毁,支持并发和并行执行。创建Goroutine使用`go`关键字,如`go sayHello("Alice")`。常见问题包括忘记使用`go`关键字、不正确处理通道同步和关闭、以及Goroutine泄漏。解决方法包括确保使用`go`启动函数、在发送完数据后关闭通道、设置Goroutine退出条件。理解并掌握这些能帮助开发者编写高效、安全的并发程序。
10 1