编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。
程序介绍
本程序实现解释器模式。程序可按需加载用户自定义的.work后缀文件,将每行的命令解释为具体行为。喵叫几次、进程休眠几秒、输出范围内随机数、运行另外的work文件。
Meow载入额外配置信息-----> 额外的配置信息
喵~喵~喵~喵~喵~
Sleep载入额外配置信息-----> 额外的配置信息
开始睡眠 3 s
Rand载入额外配置信息-----> 额外的配置信息
获取 5~10 随机数 -> 9
Sleep载入额外配置信息-----> 额外的配置信息
开始睡眠 5 s
Rand载入额外配置信息-----> 额外的配置信息
获取 100~200 随机数 -> 276
找不到该条指令的规则 疯狂星期四
Call载入额外配置信息-----> 额外的配置信息
Meow载入额外配置信息-----> 额外的配置信息
喵~喵~
找不到该条指令的规则 rand
程序执行结束
Meow载入额外配置信息-----> 额外的配置信息
喵~
程序执行结束
程序代码
data/duty.work
meow 5
sleep 3
random 5~10
sleep 5
random 100~200
疯狂星期四 v我50
call ./data/test.work
meow 1
data/test.work
meow 2
rand 0~1
methods.go
package main
import (
"fmt"
"io"
"math/rand"
"strings"
"time"
)
func meow(count int) {
fmt.Println(strings.Repeat("喵~", count))
}
func sleep(count int) {
fmt.Printf("开始睡眠 %v s\n", count)
time.Sleep(time.Second * time.Duration(count))
}
func random(start, end int) {
fmt.Printf("获取 %v~%v 随机数 -> %v\n", start, end, rand.Intn(end)+start)
}
func doWork(path string) {
c := &context{comment: "额外的配置信息"}
c.Open(path)
for {
method, err := c.Read()
if err != io.EOF {
switch method {
case "meow":
var meow expression = &MeowExpression{}
meow.Interpret(c)
case "sleep":
var sleep expression = &SleepExpression{}
sleep.Interpret(c)
case "random":
var random expression = &RandomExpression{}
random.Interpret(c)
case "call":
var call expression = &CallExpression{}
call.Interpret(c)
default:
fmt.Println("找不到该条指令的规则", method)
}
} else {
break
}
}
fmt.Println("程序执行结束")
}
doWork()
函数用于创建上下文对象,并遍历行,采用了简单工厂模式。(略有违背单一职责原则,在这里只做案例演示)
事实上每添加一种文法,就需要添加一个类,同时修改这个简单工厂,对分支判断进行修改。在这里可以用反射改进,可以参考 “我的设计模式编程之旅 ①” 来动态生成实例对象,从而符合封闭-开放原则
。
interpreter.go
package main
import (
"bufio"
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
)
type Context struct {
file *os.File
scanner *bufio.Scanner
line string // ^ 当前行
comment string // ^ 额外配置信息
}
// 打开文件并转换成 bufio.Scanner
func (c *Context) Open(path string) {
file, err := os.Open(path)
if err != nil {
log.Fatal(err)
}
c.file = file
scanner := bufio.NewScanner(file)
c.scanner = scanner
}
// 关闭 bufio.Scanner
func (c *Context) Close() {
c.file.Close()
c.file = nil
c.scanner = nil
}
// 获取当前行并将光标移到下一行
func (c *Context) Read() (string, error) {
if c.scanner == nil {
log.Fatal("no scanner")
}
if c.scanner.Scan() {
c.line = c.scanner.Text()
return strings.Split(c.line, " ")[0], nil
} else {
return "", io.EOF
}
}
type IExpression interface {
Interpret(c *Context)
}
type MeowExpression struct{}
type SleepExpression struct{}
type RandomExpression struct{}
type CallExpression struct{}
func (e MeowExpression) Interpret(c *Context) {
fmt.Println("Meow载入额外配置信息----->", c.comment)
params := strings.Split(c.line, " ")[1]
i, err := strconv.Atoi(params)
if err != nil {
log.Fatal(err)
}
meow(i)
}
fun