缘起

最近复习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采用golang练习之

建造者模式

建造者模式(Builder Pattern)将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示,属于创建型设计模式。
_

场景

  • 某业务系统, 希望使用SQLQuery类动态构造复杂SQL查询语句
  • SQLQuery类的各种属性组合情况很多, 因此创建SQLQueryBuilder作为SQLQuery的建造者

builder_test.go

测试用例

  1. package patterns
  2. import (
  3. "fmt"
  4. bd "learning/gooop/creational_patterns/builder"
  5. "testing"
  6. )
  7. func Test_Builder(t *testing.T) {
  8. builder := bd.NewSQLQueryBuilder()
  9. builder = builder.WithTable("product")
  10. builder = builder.AddField("id").AddField("name").AddField("price")
  11. builder = builder.AddCondition("enabled=1")
  12. builder = builder.WithOrderBy("price desc")
  13. query := builder.Build()
  14. fmt.Println(query.ToSQL())
  15. }

测试输出

  1. $ go test -v builder_test.go
  2. === RUN Test_Builder
  3. select id,name,price from product where enabled=1 order by price desc
  4. --- PASS: Test_Builder (0.00s)
  5. PASS
  6. ok command-line-arguments 0.002s

ISQLQuery.go

定义SQL查询表达式的接口

  1. package builder
  2. type ISQLQuery interface {
  3. ToSQL() string
  4. }

ISQLQueryBuilder.go

定义SQL查询表达式的建造者接口, 该接口定义了一系列步骤去创建复杂查询语句

  1. package builder
  2. type ISQLQueryBuilder interface {
  3. WithTable(table string) ISQLQueryBuilder
  4. AddField(field string) ISQLQueryBuilder
  5. AddCondition(condition string) ISQLQueryBuilder
  6. WithOrderBy(orderBy string) ISQLQueryBuilder
  7. Build() ISQLQuery
  8. }

tSQLQuery.go

tSQLQuery实现了ISQLQuery接口, 根据各种参数生成复杂SQL语句

  1. package builder
  2. import "strings"
  3. type tSQLQuery struct {
  4. table string
  5. fields []string
  6. conditions []string
  7. orderBy string
  8. }
  9. func newSQLQuery() *tSQLQuery {
  10. return &tSQLQuery{
  11. table: "",
  12. fields: make([]string, 0),
  13. conditions: make([]string, 0),
  14. orderBy: "",
  15. }
  16. }
  17. func (me *tSQLQuery) ToSQL() string {
  18. b := &strings.Builder{}
  19. b.WriteString("select ")
  20. for i, it := range me.fields {
  21. if i > 0 {
  22. b.WriteRune(',')
  23. }
  24. b.WriteString(it)
  25. }
  26. b.WriteString(" from ")
  27. b.WriteString(me.table)
  28. if len(me.conditions) > 0 {
  29. b.WriteString(" where ")
  30. for i, it := range me.conditions {
  31. if i > 0 {
  32. b.WriteString(" and ")
  33. }
  34. b.WriteString(it)
  35. }
  36. }
  37. if len(me.orderBy) > 0 {
  38. b.WriteString(" order by ")
  39. b.WriteString(me.orderBy)
  40. }
  41. return b.String()
  42. }

tSQLQueryBuilder.go

tSQLQueryBuilder实现了ISQLQueryBuilder接口, 为各种参数设置提供了方法

  1. package builder
  2. type tSQLQueryBuilder struct {
  3. query *tSQLQuery
  4. }
  5. func NewSQLQueryBuilder() ISQLQueryBuilder {
  6. return &tSQLQueryBuilder {
  7. query : newSQLQuery(),
  8. }
  9. }
  10. func (me *tSQLQueryBuilder) WithTable(table string) ISQLQueryBuilder {
  11. me.query.table = table
  12. return me
  13. }
  14. func (me *tSQLQueryBuilder) AddField(field string) ISQLQueryBuilder {
  15. me.query.fields = append(me.query.fields, field)
  16. return me
  17. }
  18. func (me *tSQLQueryBuilder) AddCondition(condition string) ISQLQueryBuilder {
  19. me.query.conditions = append(me.query.conditions, condition)
  20. return me
  21. }
  22. func (me *tSQLQueryBuilder) WithOrderBy(orderBy string) ISQLQueryBuilder {
  23. me.query.orderBy = orderBy
  24. return me
  25. }
  26. func (me *tSQLQueryBuilder) Build() ISQLQuery {
  27. return me.query
  28. }

建造者模式小结

建造者模式的优点
(1)封装性好,构建和表示分离。
(2)扩展性好,建造类之间独立,在一定程度上解耦。
(3)便于控制细节,建造者可以对创建过程逐步细化,而不对其他模块产生任何影响。
建造者模式的缺点
(1)需要多创建一个IBuilder对象。
(2)如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。