缘起

最近阅读 [Offer来了:Java面试核心知识点精讲(框架篇)] (王磊 , 2020.6)
本系列笔记拟采用golang练习之
Talk is cheap, show me the code.

Spring

  1. Spring基于J2EE技术实现了一套轻量级的
  2. Java Web Service系统应用框架。
  3. 它有很多优秀的特性,很多公司都选择把
  4. Spring作为产品或项目的基础开发架构。
  5. Spring的主要特性包括:
  6. 1. 轻量
  7. 2. 控制反转(Inversion of Control, IoC
  8. 3. 面向容器
  9. 4. 面向切面(AspectOriented Programming, AOP
  10. 5. 框架灵活
  11. 源码gitee地址:
  12. https://gitee.com/ioly/learning.gooop
  13. 原文链接:
  14. https://my.oschina.net/ioly

目标

  • 参考spring常用注解,使用golang编写“基于注解的静态代码增强器/生成器”
    • 配置: ComponentScan,Configuration, Bean
    • Bean声明:Component, Service, Controller
    • Bean注入:Autowried
    • AOP注解:Before, After, Around, PointCut

子目标(Day 3)

  • 添加ProjectCmd以支持项目定义
  • 添加文本扫描的辅助类:Chars.go, Tokens.go
  • 定义代码生成服务接口ICodingService及其支撑接口

设计

  • command/ProjectCmd: 项目定义指令
  • common/Chars: 字符识别辅助类
  • common/Tokens: 组合文本识别辅助类
  • service/ICodingService: 代码生成服务接口
  • service/iCodingContext: 代码生成上下文
  • service/iCodingState:状态模式下的服务状态
  • service/iCmdRunner:定义指令执行器接口,具体执行拟走责任链模式以便扩展
  • service/tInitialState:默认的服务状态

command/ProjectCmd.go

项目定义指令

  1. package project_cmd
  2. import (
  3. "errors"
  4. "fmt"
  5. "learning/gooop/spring/autogen/command"
  6. "learning/gooop/spring/autogen/common"
  7. "os"
  8. "strings"
  9. )
  10. // ProjectCmd defines a project with name and dir
  11. type ProjectCmd struct {
  12. name string
  13. dir string
  14. }
  15. // ProjectCmdBuilder parses cli input and creates a ProjectCmd instance
  16. type ProjectCmdBuilder int
  17. const gProjectCmdPrefix = "project "
  18. var gErrorInvalidProjectCmd = errors.New("invalid project cmd")
  19. func (me *ProjectCmd) String() string {
  20. return fmt.Sprintf("project %s %s", me.name, me.dir)
  21. }
  22. func (me *ProjectCmd) Apply(ctx command.ICmdContext) error {
  23. panic("implements me")
  24. }
  25. func (me *ProjectCmdBuilder) Build(line string) (error, command.ICmd) {
  26. if !common.Tokens.MatchString(line, gProjectCmdPrefix) {
  27. return nil, nil
  28. }
  29. line = strings.TrimSpace(line[len(gProjectCmdPrefix):])
  30. b,name := common.Tokens.MatchIdentifier(line)
  31. if !b {
  32. return gErrorInvalidProjectCmd, nil
  33. }
  34. line = line[len(name):]
  35. b, spaces := common.Tokens.MatchSpaces(line)
  36. if !b {
  37. return gErrorInvalidProjectCmd, nil
  38. }
  39. line = line[len(spaces):]
  40. b, dir := common.Tokens.MatchDir(line)
  41. if !b {
  42. return gErrorInvalidProjectCmd, nil
  43. }
  44. _,e := os.Stat(dir)
  45. if e != nil {
  46. return e, nil
  47. }
  48. return nil, &ProjectCmd{ name, dir }
  49. }

common/Chars.go

字符识别辅助类

  1. package common
  2. type tChars int
  3. var Chars = new(tChars)
  4. func (me *tChars) IsSpace(it rune) bool {
  5. switch it {
  6. case ' ':
  7. return true
  8. case '\t':
  9. return true
  10. case '\r':
  11. return true
  12. case '\n':
  13. return true
  14. }
  15. return false
  16. }
  17. func (me *tChars) Is09(it rune) bool {
  18. return it >= '0' && it <= '9'
  19. }
  20. func (me *tChars) Is19(it rune) bool {
  21. return it >= '1' && it <= '9'
  22. }
  23. func (me *tChars) IsLetter(it rune) bool {
  24. return (it >= 'a' && it <= 'z') || (it >= 'A' && it <= 'Z')
  25. }
  26. func (me *tChars) IsUnderscore(it rune) bool {
  27. return it == '_'
  28. }
  29. func (me *tChars) IsLB(it rune) bool {
  30. return it == '('
  31. }
  32. func (me *tChars) IsRB(it rune) bool {
  33. return it == ')'
  34. }
  35. func (me *tChars) IsChar(it rune, args... rune) bool {
  36. for _,v := range args {
  37. if v == it {
  38. return true
  39. }
  40. }
  41. return false
  42. }
  43. func (me *tChars) IsSQuote(it rune) bool {
  44. return me.IsChar(it, '\'')
  45. }
  46. func (me *tChars) IsDQuote(it rune) bool {
  47. return me.IsChar(it, '"')
  48. }
  49. func (me *tChars) IsRSplash(it rune) bool {
  50. return me.IsChar(it, '\\')
  51. }
  52. func (me *tChars) IsLSplash(it rune) bool {
  53. return me.IsChar(it, '/')
  54. }

common/Tokens.go

组合文本识别辅助类

  1. package common
  2. import (
  3. "regexp"
  4. "strings"
  5. "sync"
  6. )
  7. type tTokens struct {
  8. cache map[string]*regexp.Regexp
  9. rwmutex *sync.RWMutex
  10. }
  11. var Tokens = newTokensLib()
  12. func newTokensLib() *tTokens {
  13. it := new(tTokens)
  14. it.init()
  15. return it
  16. }
  17. func (me *tTokens) init() {
  18. me.cache = make(map[string]*regexp.Regexp)
  19. me.rwmutex = new(sync.RWMutex)
  20. }
  21. func (me *tTokens) MatchString(s string, p string) bool {
  22. return strings.HasPrefix(s, p)
  23. }
  24. func (me *tTokens) MatchRegexp(s string, p string) (bool, string) {
  25. me.rwmutex.RLock()
  26. r,ok := me.cache[p]
  27. me.rwmutex.RUnlock()
  28. if !ok {
  29. me.rwmutex.Lock()
  30. if r,ok = me.cache[p];!ok {
  31. r,_ = regexp.Compile(p)
  32. }
  33. me.rwmutex.Unlock()
  34. }
  35. if r == nil {
  36. return false, ""
  37. }
  38. if !r.MatchString(s) {
  39. return false, ""
  40. }
  41. return true, r.FindString(s)
  42. }
  43. func (me *tTokens) MatchIdentifier(s string) (bool, string) {
  44. return me.MatchRegexp(s, "^[_a-zA-Z]\\w{0,99}}")
  45. }
  46. func (me *tTokens) MatchSpaces(s string) (bool, string) {
  47. return me.MatchRegexp(s, "^\\s+")
  48. }
  49. func (me *tTokens) MatchDir(s string) (bool, string) {
  50. b,s := me.MatchRegexp(s, "^([a-zA-Z]\\:)?([\\\\/][^\\s/:*?<>|\\\"\\\\]+)+[\\/]?")
  51. if b {
  52. return b,s
  53. }
  54. b,s = me.MatchRegexp(s, "^\\\"([a-zA-Z]\\:)?([\\\\/][^/:*?<>|\\\"\\\\]+)+[\\/]?\\\"")
  55. if b {
  56. return b,s
  57. }
  58. b,s = me.MatchRegexp(s, "^'([a-zA-Z]\\:)?([\\\\/][^'/:*?<>|\\\"\\\\]+)+[\\/]?'")
  59. if b {
  60. return b,s
  61. }
  62. return false, ""
  63. }

service/ICodingService.go

代码生成服务接口

  1. package service
  2. type ICodingService interface {
  3. iCmdRunner
  4. State() iCodingState
  5. Start()
  6. }

service/iCodingContext.go

代码生成上下文

  1. package service
  2. // iCodingContext provides context info for iCodingState instance
  3. type iCodingContext interface {
  4. HandleStateChanged(state iCodingState)
  5. }

service/iCodingState.go

状态模式下的服务状态

  1. package service
  2. type iCodingState interface {
  3. iCmdRunner
  4. }

service/iCmdRunner.go

定义指令执行器接口,具体执行拟走责任链模式以便扩展

  1. package service
  2. import "learning/gooop/spring/autogen/command"
  3. // iCmdRunner runs a user cmd
  4. type iCmdRunner interface {
  5. Run(cmd command.ICmd) error
  6. }

service/tInitialState.go

默认的服务状态

  1. package service
  2. import (
  3. "errors"
  4. "learning/gooop/spring/autogen/command"
  5. )
  6. // tInitialState is the default state for a coding service
  7. // it will only accept ProjectCmd
  8. type tInitialState struct {
  9. context iCodingContext
  10. }
  11. func newInitialState(c iCodingContext) iCodingState {
  12. it := new(tInitialState)
  13. it.init(c)
  14. return it
  15. }
  16. func (me *tInitialState) init(c iCodingContext) {
  17. me.context = c
  18. }
  19. var gErrorProjectDefineRequired = errors.New("project not defined: project <name> <dir>")
  20. func (me *tInitialState) Run(cmd command.ICmd) error {
  21. panic("implement me")
  22. }

(未完待续)