设计模式之美(通过一段ID生成器代码,学习如何发现代码质量问题)GO语言版本

前篇的文章是以Java语言为讲解的,现在我们翻译为Go语言来进行简单的讲解,在线运行代码可以用:https://play.golang.org/

1. Id生成器最初版是这样的

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

//最初代码
func GetId() string {
	id := ""
	hostName, _ := os.Hostname()
	tokens := strings.Split(hostName, ".")
	if len(tokens) > 0 {
		hostName = tokens[len(tokens)-1]
	}

	var randomChars = make([]string, 8)
	for count := 0; count < 8; {
		randomAscii := rand.Intn(122)
		if randomAscii >= 48 && randomAscii <= 57 {
			randomChars[count] = string(rune(randomAscii))
			count++
		} else if randomAscii >= 65 && randomAscii <= 90 {
			randomChars[count] = string(rune(randomAscii))
			count++
		} else if randomAscii >= 97 && randomAscii <= 122 {
			randomChars[count] = string(rune(randomAscii))
			count++
		}
	}
	id = fmt.Sprintf("%s-%d-%s", hostName, time.Now().UnixNano()/1e6, strings.Join(randomChars, ""))
	return id
}

func main() {
	for i := 1; i <= 5; i++ {
		fmt.Println(GetId())
	}
}

程序执行结果如下:

c:/go/bin/go.exe build [E:/source/golang/src/newtest]
成功: 进程退出代码 0.
E:/source/golang/src/newtest/newtest.exe  [E:/source/golang/src/newtest]
zhangsujie-d1-1611891447604-mKrxC4h5
zhangsujie-d1-1611891447605-t8FeaooS
zhangsujie-d1-1611891447605-MQEyOEci
zhangsujie-d1-1611891447605-DydDsBOl
zhangsujie-d1-1611891447605-VvxLQDVQ
成功: 进程退出代码 0.

2. 第一版优化(拆分并封装成类)

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

//第一版优化
type RandomIdGenerator1 struct {
}

func (ra RandomIdGenerator1) Generate() string {
	substrOfHostName := ra.getLastfieldOfHostName()
	currentTimeMillis := time.Now().UnixNano() / 1e6
	randomString := ra.generateRandomAlphameric(8)
	id := fmt.Sprintf("%s-%d-%s", substrOfHostName, currentTimeMillis, randomString)
	return id
}

func (ra RandomIdGenerator1) getLastfieldOfHostName() string {
	substrOfHostName := ""
	hostName, _ := os.Hostname()
	tokens := strings.Split(hostName, ".")
	if len(tokens) > 0 {
		substrOfHostName = tokens[len(tokens)-1]
	}
	return substrOfHostName
}

func (ra RandomIdGenerator1) generateRandomAlphameric(length int) string {
	randomChars := make([]string, length)
	for count := 0; count < length; {
		maxAscii := int('z')
		randomAscii := rand.Intn(maxAscii)
		isDigit := randomAscii >= int('0') && randomAscii <= int('9')
		isUppercase := randomAscii >= int('A') && randomAscii <= int('Z')
		isLowercase := randomAscii >= int('a') && randomAscii <= int('z')
		if isDigit || isUppercase || isLowercase {
			randomChars[count] = string(rune(randomAscii))
			count++
		}
	}
	return strings.Join(randomChars, "")
}

func main() {

	rn1 := new(RandomIdGenerator1)
	for i := 1; i <= 5; i++ {
		fmt.Println(rn1.Generate())
	}

}

程序执行结果如下:

c:/go/bin/go.exe build [E:/source/golang/src/newtest]
成功: 进程退出代码 0.
E:/source/golang/src/newtest/newtest.exe  [E:/source/golang/src/newtest]
zhangsujie-d1-1611892006330-mKrxC4h5
zhangsujie-d1-1611892006330-t8FeaooS
zhangsujie-d1-1611892006330-MQEyOEci
zhangsujie-d1-1611892006330-DydDsBOl
zhangsujie-d1-1611892006330-VvxLQDVQ
成功: 进程退出代码 0.

3. 第二版优化(优化随机字符方法)

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

//第二版优化
type RandomIdGenerator2 struct {
}

func (ra RandomIdGenerator2) Generate() string {
	substrOfHostName := ra.getLastfieldOfHostName()
	currentTimeMillis := time.Now().UnixNano() / 1e6
	randomString := ra.generateRandomAlphameric(8)
	id := fmt.Sprintf("%s-%d-%s", substrOfHostName, currentTimeMillis, randomString)
	return id
}

func (ra RandomIdGenerator2) getLastfieldOfHostName() string {
	substrOfHostName := ""
	hostName, _ := os.Hostname()
	tokens := strings.Split(hostName, ".")
	if len(tokens) > 0 {
		substrOfHostName = tokens[len(tokens)-1]
	}
	return substrOfHostName
}

func (ra RandomIdGenerator2) generateRandomAlphameric(length int) string {
	letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	b := make([]rune, length)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func main() {

	rn2 := new(RandomIdGenerator2)
	for i := 1; i <= 5; i++ {
		fmt.Println(rn2.Generate())
	}
} 

程序执行结果如下:

c:/go/bin/go.exe build [E:/source/golang/src/newtest]
成功: 进程退出代码 0.
E:/source/golang/src/newtest/newtest.exe  [E:/source/golang/src/newtest]
zhangsujie-d1-1611903141521-BpLnfgDs
zhangsujie-d1-1611903141522-c2WD8F2q
zhangsujie-d1-1611903141522-NfHK5a84
zhangsujie-d1-1611903141522-jjJkwzDk
zhangsujie-d1-1611903141522-h9h2fhfU
成功: 进程退出代码 0.

4. 第三版优化(优化获取主机名称)

package main

import (
	"fmt"
	"math/rand"
	"os"
	"strings"
	"time"
)

//第三版优化
func getHostName() string {
	substrOfHostName := ""
	hostName, _ := os.Hostname()
	tokens := strings.Split(hostName, ".")
	if len(tokens) > 0 {
		substrOfHostName = tokens[len(tokens)-1]
	}
	return substrOfHostName
}

var hostName = getHostName()

type RandomIdGenerator3 struct {
}

func (ra RandomIdGenerator3) Generate() string {
	currentTimeMillis := time.Now().UnixNano() / 1e6
	randomString := ra.generateRandomAlphameric(8)
	id := fmt.Sprintf("%s-%d-%s", hostName, currentTimeMillis, randomString)
	return id
}

func (ra RandomIdGenerator3) generateRandomAlphameric(length int) string {
	letterRunes := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
	b := make([]rune, length)
	for i := range b {
		b[i] = letterRunes[rand.Intn(len(letterRunes))]
	}
	return string(b)
}

func main() {

	rn3 := new(RandomIdGenerator3)
	for i := 1; i <= 5; i++ {
		fmt.Println(rn3.Generate())
	}
} 

程序执行结果如下:

c:/go/bin/go.exe build [E:/source/golang/src/newtest]
成功: 进程退出代码 0.
E:/source/golang/src/newtest/newtest.exe  [E:/source/golang/src/newtest]
zhangsujie-d1-1611903748157-BpLnfgDs
zhangsujie-d1-1611903748157-c2WD8F2q
zhangsujie-d1-1611903748157-NfHK5a84
zhangsujie-d1-1611903748157-jjJkwzDk
zhangsujie-d1-1611903748157-h9h2fhfU
成功: 进程退出代码 0.

5.这样写行不行?

package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/google/uuid"
)

func main() {
	//以下这样可不可以??
	fmt.Println(fmt.Sprintf("%d-%d", time.Now().UnixNano(), rand.Intn(89999999)+10000000))
	fmt.Println(uuid.New().String())
} 

程序执行结果如下:

c:/go/bin/go.exe build [E:/source/golang/src/newtest]
成功: 进程退出代码 0.
E:/source/golang/src/newtest/newtest.exe  [E:/source/golang/src/newtest]
1611904029112094900-48498095
082f14ba-cdec-49ce-8c5f-d9194d429425
成功: 进程退出代码 0.

总的来说,技术的实现是为业务来服务的,如果只是为了生成一个日志id方便上下游来排查问题,直接用一个简单的方法也没有问题。

代码质量问题,可以参考一个工具。

项目地址:https://github.com/360EntSecGroup-Skylar/goreporter

演示示例:http://wgliang.github.io/pages/goreporter-report.html

此条目发表在 网站开发 分类目录。将固定链接加入收藏夹。

设计模式之美(通过一段ID生成器代码,学习如何发现代码质量问题)GO语言版本》有 3 条评论

  1. xtgxiso 说:

    一个项目要考虑的问题有那些?