这两天写一些代码,发现有不少重复劳动,因此借此机会梳理下代码是怎样进化的,以密码验证位例。
密码验证规则:
1.长度超过8位。
2.包括大小写字母.数字.其它符号,以上四种至少三种。
3.不能有长度大于2的包含公共元素的子串重复。
这三种规则通常我们会写三个函数就可以搞定,见下。
package main
import "fmt"
func main(){
var s string
fmt.Scanf("%s", &s)
ResStatus := "OK"
if len(s) < 8 {
ResStatus = "NG"
} else if !incThreeVarChars(s) {
ResStatus = "NG"
} else if !existSubstrLessThann(s, 3) {
ResStatus = "NG"
}
fmt.Println(ResStatus)
}
// 包含三种字符
func incThreeVarChars(s string)bool{
tp := make(map[byte]bool)
for _,v := range s {
if isNumber(byte(v)) {
tp['1'] = true
} else if isEngUpperChar(byte(v)) {
tp['2'] = true
} else if isEngLowerChar(byte(v)) {
tp['3'] = true
} else {
tp['4'] = true
}
}
if len(tp) < 3 {
return false
}
return true
}
// 是数字
func isNumber(a byte)bool{
if a >= '0' && a <= '9' {
return true
}
return false
}
// 是大写字母
func isEngUpperChar(a byte)bool{
if a >= 'A' && a <= 'Z' {
return true
}
return false
}
// 是小写字母
func isEngLowerChar(a byte)bool{
if a >= 'a' && a <= 'z' {
return true
}
return false
}
// 是否存在低于n个字符相同子串
func existSubstrLessThann(s string, n)bool{
f := true
if len(s) <= n {
return f
}
for i := 0; i < len(s)-n;i++{
s1 := s[i:i+n]
for j := i+1; j < len(s)-n;j++{
s2 := s[j:j+n]
if s1 != s2 {
continue
}
f = false
break
}
}
return f
}
如果现在需要对这个密码验证器扩展为需要返回错误提示,我们需要更改代码并对每种规则返回对应的错误,若规则比较多这中编码不符合代码的修改哲学。
这里我把它改为一个验证器,一个规则接口,以及具体实现三块,期中验证器三个方法,AddRule是添加规则,Valide是验证规则,Error是错误收集器。
type Validator struct{
r []IRule
}
func New()*Validator{
return &Validator{}
}
func (s *Validator)AddRule(r rule){
s.r = append(s.r, r)
}
func (s *Validator)Valide(){
for _,v := range s.r {
if err := v.Valid(); err != nil {
s.errs = append(s.errs, err)
}
}
}
func (s *Validator)Errors()[]error{
return s.errs
}
规则接口只需要Valid方法,以及Rule规则具体error类型。
type IRule interface {
Valid(interface)error
}
type Rule struct {
err error
IRule
}
规则实现1,包含至少3种字符。
// 包含三种字符
type moreThanThreeKindsCharactorRule struct {
Rule
}
func (s *moreThanThreeKindsCharactorRule)Valid(s string)error{
tp := make(map[byte]bool)
for _,v := range s {
if isNumber(byte(v)) {
tp['1'] = true
} else if isEngUpperChar(byte(v)) {
tp['2'] = true
} else if isEngLowerChar(byte(v)) {
tp['3'] = true
} else {
tp['4'] = true
}
}
if len(tp) < 3 {
return errors.New("少于超过3种字符")
}
return nil
}
// 是数字
func (s *moreThanThreeKindsCharactorRule)isNumber(a byte)bool{
if a >= '0' && a <= '9' {
return true
}
return false
}
// 是大写字母
func (s *moreThanThreeKindsCharactorRule)isEngUpperChar(a byte)bool{
if a >= 'A' && a <= 'Z' {
return true
}
return false
}
// 是小写字母
func (s *moreThanThreeKindsCharactorRule)isEngLowerChar(a byte)bool{
if a >= 'a' && a <= 'z' {
return true
}
return false
}
规则实现2,存在超过n个字符的子串。
// 是否存在低于n个字符相同子串
type existSubstrLessThannRule struct{
Rule
}
func (s *existSubstrLessThannRule)Valid(s string, n int)error{
f := true
if len(s) <= n {
return f
}
for i := 0; i < len(s)-n;i++{
s1 := s[i:i+n]
for j := i+1; j < len(s)-n;j++{
s2 := s[j:j+n]
if s1 != s2 {
continue
}
f = false
break
}
}
if !f {
return errors.New("存在低于3个字符相同子串")
}
return nil
}
代码调用
func main(){
var s string
fmt.Scanf("%s", &s)
ResStatus := "OK"
validator := NewValidator()
validator.AddRule(moreThanThreeKindsCharactorRule{})
validator.AddRule(existSubstrLessThannRule{})
validator.Valide()
if errs := validator.Errors(); len(errs) > 0 {
ResStatus = "NG"
}
fmt.Println(ResStatus)
}
这种方式减少了更改以往的代码,但每增加一种规则需要增加一个struct。