There are multiple condition checks in multiple functions
type VA struct {
A string
}
func (va *VA) CheckA(s string) error {
if s != va.A {
return errors.New("invalid str ")
}
return nil
}
type VB struct {
B int
}
func (vb *VB) CheckB(i int) error {
if i == vb.B {
return errors.New("invalid int")
}
return nil
}
func FuncA(s string, i int) error {
a := &VA{A: "testa"}
errA := a.CheckA(s)
if errA != nil {
return errA
}
b := &VB{B: 3}
errB := b.CheckB(i)
if errB != nil {
return errB
}
// more logic ...
return nil
}
func FuncB(sb string, v int32) error {
a := &VA{A: "testb"}
errA := a.CheckA(sb)
if errA != nil {
return errA
}
// more logic ...
return nil
}
func FuncC(sc string, vv int) error {
b := &VB{B: 3}
errB := b.CheckB(vv)
if errB != nil {
return errB
}
// more logic ...
return nil
}
We do CheckA and CheckB in function FuncA and do CheckA in function FuncB. However, only do CheckB in function FuncC. There is one pitfall that when the return value of CheckA is changed, both FuncA and FuncB would be changed.
We want to refactor the above codes. Is there any elegant way to do that in Golang?
What we have tried, combine CheckA and CheckB in one function ValidateFunc like below
type VALIDATE int
const (
_ VALIDATE = 1 << iota
VALIDATEA
VALIDATEB
)
func ValidateFunc(vs, s string, vi, i int, validate VALIDATE) error {
if validate&VALIDATEA == VALIDATEA {
a := &VA{A: vs}
errA := a.CheckA(s)
if errA != nil {
return errA
}
}
if validate&VALIDATEB == VALIDATEB {
b := &VB{B: vi}
errB := b.CheckB(i)
if errB != nil {
return errB
}
}
return nil
}
func FuncA(s string, i int) error {
err := ValidateFunc("testa", s, 3, i, VALIDATEA|VALIDATEB)
if err != nil {
return err
}
// more logic ...
return nil
}
CodePudding user response:
Refer to Option pattern, it seems the codes will be simpler than before.
type Validator struct {
A VA
B VB
}
type Validate func(v *Validator) error
func WithVA(s string) Validate {
return func(v *Validator) error {
if err := v.A.CheckA(s); err != nil {
return err
}
return nil
}
}
func WithVB(i int) Validate {
return func(v *Validator) error {
if err := v.B.CheckB(i); err != nil {
return err
}
return nil
}
}
func DoValidate(vs string, vi int, vals ...func(v *Validator) error) error {
v := &Validator{A: VA{A: vs}, B: VB{B: vi}}
for _, val := range vals {
if err := val(v); err != nil {
return err
}
}
return nil
}
func FuncA(s string, i int) error {
err := DoValidate("testa", 3, WithVA(s), WithVB(i))
if err != nil {
return err
}
// more logic ...
return nil
}
CodePudding user response:
Perhaps combine VA & VB into a new struct Then validate that one?
