Elegant way to eliminate multiple condition checks in function

huangapple go评论105阅读模式
英文:

Elegant way to eliminate multiple condition checks in function

问题

有多个函数中有多个条件检查。

  1. type VA struct {
  2. A string
  3. }
  4. func (va *VA) CheckA(s string) error {
  5. if s != va.A {
  6. return errors.New("无效的字符串")
  7. }
  8. return nil
  9. }
  10. type VB struct {
  11. B int
  12. }
  13. func (vb *VB) CheckB(i int) error {
  14. if i == vb.B {
  15. return errors.New("无效的整数")
  16. }
  17. return nil
  18. }
  19. func FuncA(s string, i int) error {
  20. a := &VA{A: "testa"}
  21. errA := a.CheckA(s)
  22. if errA != nil {
  23. return errA
  24. }
  25. b := &VB{B: 3}
  26. errB := b.CheckB(i)
  27. if errB != nil {
  28. return errB
  29. }
  30. // 更多逻辑...
  31. return nil
  32. }
  33. func FuncB(sb string, v int32) error {
  34. a := &VA{A: "testb"}
  35. errA := a.CheckA(sb)
  36. if errA != nil {
  37. return errA
  38. }
  39. // 更多逻辑...
  40. return nil
  41. }
  42. func FuncC(sc string, vv int) error {
  43. b := &VB{B: 3}
  44. errB := b.CheckB(vv)
  45. if errB != nil {
  46. return errB
  47. }
  48. // 更多逻辑...
  49. return nil
  50. }

我们在函数FuncA中进行了CheckACheckB,在函数FuncB中进行了CheckA。然而,在函数FuncC中只进行了CheckB。有一个问题是,当CheckA的返回值发生变化时,FuncAFuncB都需要进行修改。

我们想要重构上述代码。在Golang中是否有一种优雅的方式来实现这一点?

我们尝试将CheckACheckB合并到一个名为ValidateFunc的函数中,如下所示:

  1. type VALIDATE int
  2. const (
  3. _ VALIDATE = 1 << iota
  4. VALIDATEA
  5. VALIDATEB
  6. )
  7. func ValidateFunc(vs, s string, vi, i int, validate VALIDATE) error {
  8. if validate&VALIDATEA == VALIDATEA {
  9. a := &VA{A: vs}
  10. errA := a.CheckA(s)
  11. if errA != nil {
  12. return errA
  13. }
  14. }
  15. if validate&VALIDATEB == VALIDATEB {
  16. b := &VB{B: vi}
  17. errB := b.CheckB(i)
  18. if errB != nil {
  19. return errB
  20. }
  21. }
  22. return nil
  23. }
  24. func FuncA(s string, i int) error {
  25. err := ValidateFunc("testa", s, 3, i, VALIDATEA|VALIDATEB)
  26. if err != nil {
  27. return err
  28. }
  29. // 更多逻辑...
  30. return nil
  31. }
英文:

There are multiple condition checks in multiple functions

  1. type VA struct {
  2. A string
  3. }
  4. func (va *VA) CheckA(s string) error {
  5. if s != va.A {
  6. return errors.New(&quot;invalid str &quot;)
  7. }
  8. return nil
  9. }
  10. type VB struct {
  11. B int
  12. }
  13. func (vb *VB) CheckB(i int) error {
  14. if i == vb.B {
  15. return errors.New(&quot;invalid int&quot;)
  16. }
  17. return nil
  18. }
  19. func FuncA(s string, i int) error {
  20. a := &amp;VA{A: &quot;testa&quot;}
  21. errA := a.CheckA(s)
  22. if errA != nil {
  23. return errA
  24. }
  25. b := &amp;VB{B: 3}
  26. errB := b.CheckB(i)
  27. if errB != nil {
  28. return errB
  29. }
  30. // more logic ...
  31. return nil
  32. }
  33. func FuncB(sb string, v int32) error {
  34. a := &amp;VA{A: &quot;testb&quot;}
  35. errA := a.CheckA(sb)
  36. if errA != nil {
  37. return errA
  38. }
  39. // more logic ...
  40. return nil
  41. }
  42. func FuncC(sc string, vv int) error {
  43. b := &amp;VB{B: 3}
  44. errB := b.CheckB(vv)
  45. if errB != nil {
  46. return errB
  47. }
  48. // more logic ...
  49. return nil
  50. }

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

  1. type VALIDATE int
  2. const (
  3. _ VALIDATE = 1 &lt;&lt; iota
  4. VALIDATEA
  5. VALIDATEB
  6. )
  7. func ValidateFunc(vs, s string, vi, i int, validate VALIDATE) error {
  8. if validate&amp;VALIDATEA == VALIDATEA {
  9. a := &amp;VA{A: vs}
  10. errA := a.CheckA(s)
  11. if errA != nil {
  12. return errA
  13. }
  14. }
  15. if validate&amp;VALIDATEB == VALIDATEB {
  16. b := &amp;VB{B: vi}
  17. errB := b.CheckB(i)
  18. if errB != nil {
  19. return errB
  20. }
  21. }
  22. return nil
  23. }
  24. func FuncA(s string, i int) error {
  25. err := ValidateFunc(&quot;testa&quot;, s, 3, i, VALIDATEA|VALIDATEB)
  26. if err != nil {
  27. return err
  28. }
  29. // more logic ...
  30. return nil
  31. }

答案1

得分: 1

参考选项模式,代码似乎比以前更简单。

  1. type Validator struct {
  2. A VA
  3. B VB
  4. }
  5. type Validate func(v *Validator) error
  6. func WithVA(s string) Validate {
  7. return func(v *Validator) error {
  8. if err := v.A.CheckA(s); err != nil {
  9. return err
  10. }
  11. return nil
  12. }
  13. }
  14. func WithVB(i int) Validate {
  15. return func(v *Validator) error {
  16. if err := v.B.CheckB(i); err != nil {
  17. return err
  18. }
  19. return nil
  20. }
  21. }
  22. func DoValidate(vs string, vi int, vals ...func(v *Validator) error) error {
  23. v := &Validator{A: VA{A: vs}, B: VB{B: vi}}
  24. for _, val := range vals {
  25. if err := val(v); err != nil {
  26. return err
  27. }
  28. }
  29. return nil
  30. }
  31. func FuncA(s string, i int) error {
  32. err := DoValidate("testa", 3, WithVA(s), WithVB(i))
  33. if err != nil {
  34. return err
  35. }
  36. // more logic ...
  37. return nil
  38. }
英文:

Refer to Option pattern, it seems the codes will be simpler than before.

  1. type Validator struct {
  2. A VA
  3. B VB
  4. }
  5. type Validate func(v *Validator) error
  6. func WithVA(s string) Validate {
  7. return func(v *Validator) error {
  8. if err := v.A.CheckA(s); err != nil {
  9. return err
  10. }
  11. return nil
  12. }
  13. }
  14. func WithVB(i int) Validate {
  15. return func(v *Validator) error {
  16. if err := v.B.CheckB(i); err != nil {
  17. return err
  18. }
  19. return nil
  20. }
  21. }
  22. func DoValidate(vs string, vi int, vals ...func(v *Validator) error) error {
  23. v := &amp;Validator{A: VA{A: vs}, B: VB{B: vi}}
  24. for _, val := range vals {
  25. if err := val(v); err != nil {
  26. return err
  27. }
  28. }
  29. return nil
  30. }
  31. func FuncA(s string, i int) error {
  32. err := DoValidate(&quot;testa&quot;, 3, WithVA(s), WithVB(i))
  33. if err != nil {
  34. return err
  35. }
  36. // more logic ...
  37. return nil
  38. }

答案2

得分: -1

也许将VA和VB合并成一个新的结构体,然后验证它?

英文:

Perhaps combine VA & VB into a new struct
Then validate that one?

huangapple
  • 本文由 发表于 2022年1月25日 16:54:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/70845815.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定