571
社区成员
发帖
与我相关
我的任务
分享1. 为建立LinkTable以链表形式保存指令需要创建指令结点LinkTableNode。
2. 指令结点包含:指令调用名、指令描述、接口实现指令操作以及指向下一指令的指针。
3. 指令结点结构体的方法有:一个启用指令操作的方法。
4. LinkTableNode还有一个创建指令结点的函数。其实现如下:
package menu
//指令结点
type LinkTableNode struct{
cmd_s string
desc string
cmd_do CmdDo
next *LinkTableNode
}
//指令操作
type CmdDo interface{
do()
}
//节点相关
func (this *LinkTableNode)GetNextLinkTableNode() *LinkTableNode {
if this != nil {
return this.next
}
return nil
}
func(this *LinkTableNode)Do() {
this.cmd_do.do()
}
func CreateCmd(name string, desc string, cmd_do CmdDo) *LinkTableNode{
return &LinkTableNode{
cmd_s : name,
desc : desc,
cmd_do : cmd_do,
next : nil,
}
}
1. 因为Menu程序只有一个,故根据其应用场景,使用单例模式创建一个全局的List指针保存指令集合,使用sync.Do保证List只初始化一次,且在导入使用menu包时自动初始化。
2. LinkTable结构体包含head和tail指针用于查找和插入指令到指令链表中,cnt计数记录指令个数。注:因为使用方法实现对LinkTable的一系列操作,故不需要使用互斥锁mutex,否则会造成死锁。
//指令列表
type LinkTable struct{
head *LinkTableNode
tail *LinkTableNode
cnt int
}
3. 定义LinkTable的一系列操作,包括指令结点的增加,删除,查找,执行操作。注:Go语言有内存自动回收机制,故不需要定义手动删除释放所有结点的操作
1)方法:Add_LinkTableNode。功能:将指令结点加入到LinkTable中。
func (this *LinkTable)Add_LinkTableNode(newC *LinkTableNode) error{
//先看结点是否存在
p := this.FindCmd(newC.cmd_s)
if p != nil {
return errors.New("Exit same command")
}
if this.cnt >= MAX_CMD {
return errors.New("Full cmd!")
}
if this.head == nil {
this.head = newC
this.tail = newC
this.cnt = 1
return nil
}
this.cnt++;
this.tail.next = newC
this.tail = this.tail.next
return nil
}
2)方法:FindCmd。功能:查找指令并返回对应指针。
func (this *LinkTable)FindCmd(cmd string) *LinkTableNode {
for p := this.head; p!= nil; p = p.next {
if p.cmd_s == cmd {
return p
}
}
return nil
}
3)方法:Del_LinkTableNode1。功能:根据指令名删除对应指令。
func (this *LinkTable)Del_LinkTableNode1(cmd string) error{
if this.head == nil {
return errors.New("Empty")
}
if this.head.cmd_s == cmd {
this.head = this.head.next
if this.head == nil {
this.tail = this.head
}
return nil
}
pre := this.head
for p:=pre.next; p != nil;{
if p.cmd_s == cmd {
pre.next = p.next
if this.tail == p {
this.tail = pre
}
return nil
}
pre = p
p = p.next
}
return errors.New("Doesn't exit")
}
4)方法:GetLinkTableHead。功能:返回指令链表的头节点,因为结构体中首字母小写的属性对与包外是不可访问的。
func (this *LinkTable)GetLinkTableHead() *LinkTableNode{
if this.head == nil {
return nil
}
return this.head
}
5)方法:GetNextLinkTableNode。功能:获取得到下一个指令结点
func (this *LinkTable)GetNextLinkTableNode(pNode *LinkTableNode) *LinkTableNode {
if this == nil || pNode == nil {
return nil
}
for p := this.head; p != nil; p = p.next{
if p == pNode {
return p.next
}
}
return nil
}
6)方法:Process。功能:执行对应指令
func (this *LinkTable)Process(cmd string) error{
p := this.FindCmd(cmd)
if p!= nil {
p.Do()
return nil
}
return errors.New("error cmd")
}
最后为了更方便的调用运行menu程序,创建一个menu包,其中包含menu程序的一系列用户接口操作,目前实现了配置menu加入指令,以及运行menu程序的函数。
package menu
import "fmt"
func init() {
go MenuConfig("help", "show all command and descirbe!", new(Cmd_help))
go MenuConfig("quit", "quit the Menu!", new(Cmd_quit))
go MenuConfig("ls", "show all file list", new(Cmd_ls))
}
func MenuConfig(cmd_s string, desc string, cmd_do CmdDo) {
p := CreateCmd(cmd_s, desc, cmd_do)
err := List.Add_LinkTableNode(p)
if err != nil {
fmt.Println(err)
}
}
func ExecuteMenu() {
var cmd string
for{
fmt.Printf("%s :", "Input a cmd number >")
fmt.Scanln(&cmd)
err := List.Process(cmd)
if err != nil {
fmt.Println(err)
}
}
}
1. 使用接口实现对应指令的操作,这样指令可以分模块,更多样化的去创建,实现多态。
2. 指令操作只需将实现的指令操作结构体,加入到对应指令节点中即可。
3. 通过接口实现的指令操作参数可以更多样且结构体可以保存参数,也就是操作可以保存对应的配置参数。
4. 输入参数可以使用空指针实习不定长,不定类型参数。
以下是简单指令的部分实现:
package menu
import "fmt"
//指令操作相关
type Cmd_help struct {
}
func (this Cmd_help)do() {
fmt.Println("Commands in Menu:")
p := List.head
for p != nil {
fmt.Printf("%s : %s \n", p.cmd_s, p.desc)
p = p.next
}
}
type Cmd_quit struct {
}
func (this Cmd_quit)do() {
panic("Quit!")
}
type Cmd_ls struct {
}
func (this Cmd_ls)do() {
fmt.Println("file1, file2, file3.....")
}
作者:313