20、做中学 | 初升高 | 考场三 | 三层架构-客户信息管理软件

王者杯·14天创作挑战营·第8期 10w+人浏览 290人参与

本篇引导:分层开发对应的程序!学过其它后端开发,一定知道控制层controller、服务层service、数据访问层dao,那么在go中如何编写呢?

一、需求讨论

开发一个客户信息管理软件,进行维护客户信息!客户信息有姓名、年龄、性别、电话、邮箱,获取这些信息并进行维护到客户信息库中!
维护信息的过程包含以下功能:

  1. 提供与用户交互的菜单界面
  2. 添加用户
  3. 删除用户
  4. 修改用户
  5. 退出程序

1. 提取菜单需求

菜单UI如下
在这里插入图片描述
进行展示软件功能,进行用户交互,需要循环执行

2. 提取添加用户需求

添加用户需求如下
在这里插入图片描述
获取客户姓名、年龄、性别、电话、邮箱信息

3.提取删除用户需求

在这里插入图片描述
输入要删除的用户id,进行删除用户

4. 提取修改用户需求

在这里插入图片描述
输入要修改的用户id,并获取用户要修改的属性

5. 提取退出程序需求

在这里插入图片描述
退出程序,需要做出二次确认

二、分层讨论

1. 实体层

本次需求是对客户信息的维护,客户信息包含姓名、年龄、性别、电话、邮箱

根据这些信息,进行构建结构体,并通过工厂模式返回一个全参的构建结构体对象。

2. 逻辑层

根据需求可以看到客户信息管理软件主要有添加客户、修改客户、删除客户、退出软件功能,

由于是模拟,没有数据进行维护新增的数据,所以在逻辑层需要添加俩个属性:1. 客户信息列表,2:客户id,并通过工厂模式返回一个结构体对象(属性没有初始化)。

3. 控制层

进行接收用户信息并进行转发到逻辑层!

本次需求为菜单,进行在控制层维护一个菜单交互,并根据用户选项,进行正确转发处理。

三、代码完善

1. 实体层

构建客户Customer结构体,并进行返回创建的实体对象

package model

import "fmt"

// Customer 客户信息结构体
type Customer struct {
	Id    int
	Name  string
	Age   int
	Sex   string
	Tel   string
	Email string
}

// NewCustomer 工厂模式返回一个指针的 Customer(可以理解为有参构造函数 带了个返回实体的方法)
func NewCustomer(id int, name string, age int, sex string, tel string, email string) *Customer {
	return &Customer{
		Id:    id,
		Name:  name,
		Age:   age,
		Sex:   sex,
		Tel:   tel,
		Email: email,
	}
}

// NewCustomer2 工厂模式返回一个指针的 Customer(可以理解为有参构造函数 带了个返回实体的方法)
func NewCustomer2(name string, age int, sex string, tel string, email string) Customer {
	return Customer{
		Name:  name,
		Age:   age,
		Sex:   sex,
		Tel:   tel,
		Email: email,
	}
}

// GetInfo 获取客户信息
func (this *Customer) GetInfo() string {
	return fmt.Sprintf("%d\t%s\t%d\t%s\t%s\t%s", this.Id, this.Name, this.Age, this.Sex, this.Tel, this.Email)
}

2. 逻辑层

添加客户信息的增删改查功能

package service

import (
	"fmt"
	"learn_golang_project/src/go_code/grade110/model"
)

type CustomerService struct {
	// 客户数组
	customers []model.Customer

	// 客户id
	customerNum int
}

func NewCustomerService() *CustomerService {
	return &CustomerService{}
}

func (this *CustomerService) List() {
	if len(this.customers) == 0 {
		fmt.Println("没有客户信息")
	} else {
		for _, customer := range this.customers {
			fmt.Println(customer.GetInfo())
		}
	}
}

// Add 添加客户
func (this *CustomerService) Add(customer model.Customer) bool {
	// 算出id
	this.customerNum++
	// id赋值
	customer.Id = this.customerNum

	// 追加列表
	this.customers = append(this.customers, customer)
	return true
}

// Delete 删除用户
func (this *CustomerService) Delete(id int) bool {
	if id > len(this.customers) {
		// 切片没内容直接返回处理成功
		return true
	} else {
		// 切片remove是 掐头去尾 然后拼接
		// 这里先进行获取id对应的下标
		removeIdx := -1
		for index, customer := range this.customers {
			if customer.Id == id {
				removeIdx = index
			}
		}
		if removeIdx == -1 {
			return false
		}
		this.customers = append(this.customers[:removeIdx], this.customers[removeIdx+1:]...)
		return true
	}
}

// Get 获取用户
func (this *CustomerService) Get(update int) *model.Customer {
	for _, customer := range this.customers {
		if customer.Id == update {
			return &customer
		}
	}
	return model.NewCustomer(0, "", 0, "", "", "")
}

// Update 修改用户
func (this *CustomerService) Update(modelCustomer *model.Customer) bool {
	for index := range this.customers {
		if this.customers[index].Id == modelCustomer.Id {
			this.customers[index] = *modelCustomer
			return true
		}
	}
	return false
}

// Exit 退出
func (this *CustomerService) Exit() bool {
	fmt.Println("确认是否退出:(Y/N)")
	flag := ""
	for {
		fmt.Scanln(&flag)
		if flag == "Y" || flag == "N" || flag == "y" || flag == "n" {
			break
		}
		fmt.Println("请输入正确的选项")
	}

	if flag == "Y" || flag == "y" {
		fmt.Println("退出")
		return true
	}
	return false
}

3. 控制层

完善用户交互逻辑和转发处理

package main

import (
	"fmt"
	"learn_golang_project/src/go_code/grade110/model"
	"learn_golang_project/src/go_code/grade110/service"
)

// 通过service对数据层进行操作:添加、删除、修改、查询

type CustomerView struct {
	// 用户输入值
	key string

	// 是否循环
	loop bool

	// 添加处理层声明
	service *service.CustomerService
}

// NewCustomerView 实例化业务处理对象 并初始化属性
func NewCustomerView() *CustomerView {
	return &CustomerView{
		key:     "",
		loop:    false,
		service: service.NewCustomerService(),
	}
}

// MainMenu 菜单
func (this *CustomerView) MainMenu() {
	for {
		fmt.Println("-------------客户信息管理软件-------------")
		fmt.Println("                 1 添加客户")
		fmt.Println("                 2 修改客户")
		fmt.Println("                 3 删除客户")
		fmt.Println("                 4 客户列表")
		fmt.Println("                 5 退出软件")

		fmt.Println("请选择(1-5):")
		fmt.Scanln(&this.key)

		switch this.key {
		case "1":
			// 添加客户信息
			// 1. 收集信息
			// 2. 添加信息到存储地
			//     2.1 分析存储地是哪里?:本次练习为切片容器
			//     2.2 分析切片接收什么类型的数据?:Customer
			//     2.3 如何创建一个Customer对象?
			//     2.4 Customer对象和用户的信息怎么映射?
			// 3. 处理结果是否成功
			fmt.Println("------------添加客户------------")
			// 1. 收集信息
			name := ""
			fmt.Println("姓名:")
			fmt.Scanln(&name)

			age := 0
			fmt.Println("年龄:")
			fmt.Scanln(&age)

			sex := ""
			fmt.Println("性别:")
			fmt.Scanln(&sex)

			tel := ""
			fmt.Println("手机:")
			fmt.Scanln(&tel)

			email := ""
			fmt.Println("邮箱:")
			fmt.Scanln(&email)

			// 2. 添加信息到存储地
			//     2.2 分析切片接收什么类型的数据?:Customer
			//     2.3 如何创建一个Customer对象?
			//     2.4 Customer对象和用户的信息怎么映射?
			customer2 := model.NewCustomer2(name, age, sex, tel, email)

			//     2.1 分析存储地是哪里?:本次练习为切片容器
			addResult := this.service.Add(customer2)

			// 3. 处理结果是否成功
			if addResult {
				fmt.Println("添加成功")
			} else {
				fmt.Println("添加失败")
			}
			fmt.Println("------------添加客户完成------------")
		case "2":
			// 1. 获取要修改的用户id
			// 2. 查询对应的用户信息
			// 3. 获取用户信息
			// 4. 从切片中找到对应的id
			// 5. 修改信息
			// 6. 处理结果是否成功
			fmt.Println("------------修改客户------------")
			// 1. 获取要修改的用户id
			idUpdate := -1
			fmt.Println("请输入要修改的id:(-1为退出修改)")
			fmt.Scanln(&idUpdate)
			if idUpdate == -1 {
				continue
			}

			// 2. 查询对应的用户信息
			customer := this.service.Get(idUpdate)
			if customer.Id == 0 {
				fmt.Println("没有此用户")
				continue
			}

			// 3. 获取用户信息
			fmt.Printf("姓名(%s):\n", customer.Name)
			fmt.Scanln(&customer.Name)

			fmt.Printf("年龄(%d):\n", customer.Age)
			fmt.Scanln(&customer.Age)

			fmt.Printf("性别(%s):\n", customer.Sex)
			fmt.Scanln(&customer.Sex)

			fmt.Printf("电话(%s):\n", customer.Tel)
			fmt.Scanln(&customer.Tel)

			fmt.Printf("邮箱(%s):\n", customer.Email)
			fmt.Scanln(&customer.Email)

			// 4. 从切片中找到对应的id
			// 5. 修改信息
			updateResult := this.service.Update(customer)

			// 6. 处理结果是否成功
			if updateResult {
				fmt.Println("修改成功")
			} else {
				fmt.Println("修改失败")
			}
			fmt.Println("------------修改客户成功------------")
		case "3":
			// 1. 获取用户要删除的id
			// 2. 操作从存储地删除:切片容器中,删除对应的id
			// 3. 处理结果是否成功
			fmt.Println("------------删除客户------------")
			// 1. 获取用户要删除的id
			id := -1
			fmt.Println("请输入要删除的id:")
			fmt.Scanln(&id)

			if id < 0 {
				fmt.Println("请输入正确的id")
				continue
			}

			// 2. 操作从存储地删除:切片容器中,删除对应的id
			deleteResult := this.service.Delete(id)

			// 3. 处理结果是否成功
			if deleteResult {
				fmt.Println("删除成功")
			} else {
				fmt.Println("删除失败")
			}
			fmt.Println("------------删除客户完成------------")
		case "4":
			fmt.Println("------------客户列表------------")
			this.service.List()
			fmt.Println("-------------客户列表完成-------------")
		case "5":
			this.loop = this.service.Exit()
		}

		if this.loop {
			break
		}
	}

	fmt.Println("你退出了客户信息管理软件")
}

func main() {
	customerView := NewCustomerView()
	customerView.MainMenu()
}

本次项目为三层结构,比较常见的后台分层处理,现在好像前端框架也开始了分层处理思想!

分层与不分层有什么区别呢?从功能上没有什么区别!但是从开发和维护角度,需要进行分层处理!这样做的目的,是使代码结构更清晰,维护成本更小!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值