创建型模式主要目标是提供一种灵活方式创建对象,同事隐藏创建的具体细节,降低代码耦合度,提高复用性和可维护性。
创建型模式-单例
单例模式,Singleton, 确保只有一实例,并提供全局访问点。
使用场景:配置管理,日志记录, 数据库连接池等。
global.DB, global.Config 并不是单例模式,而是直接使用全局变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package database
import "sync"
type DB struct { }
var db *DB
var once sync.Once
func initDB(dsn string) *DB { return &DB{} }
func GetDB() *DB { once.Do(func() { db = initDB("xxx") }) return db }
|
单测:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package database
import ( "fmt" "testing" )
func TestGetDB(t *testing.T) { db1 := GetDB() db2 := GetDB() db3 := GetDB()
fmt.Printf("%p\n", db1) fmt.Printf("%p\n", db2) fmt.Printf("%p\n", db3) }
|
创建型模式-简单工厂模式
目标是将对象的创建和使用分离,解耦合
简单工厂模式:一个工厂类负责创建所有产品,通过条件判断来决定创建哪种产品。
简单工厂并不是正式的设计模式,而是一种编程习惯。(所以有23种设计模式,和24种设计模式两种说法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package factory_pay
type Pay interface { PayPage(price int64) (string, error) }
type AliPay struct{}
func (p *AliPay) PayPage(price int64) (string, error) { return "aliPay", nil }
type WexinPay struct{}
func (p *WexinPay) PayPage(price int64) (string, error) { return "wexinPay", nil }
type PayType int8
const ( AliPayType = 1 WexinPayType = 2 )
func NewPayPage(payType PayType) Pay { switch payType { case AliPayType: return &AliPay{} case WexinPayType: return &WexinPay{} } return nil }
|
单测:
1 2 3 4 5 6 7 8 9 10 11 12 13
| package factory_pay
import ( "fmt" "testing" )
func TestNewPayPage(t *testing.T) { page, _ := NewPayPage(WexinPayType).PayPage(1) payPage, _ := NewPayPage(AliPayType).PayPage(1) fmt.Println(page) fmt.Println(payPage) }
|
创建型模式-工厂方法模式
工厂方法模式定义了一个创建对象接口,单具体的创建逻辑延迟到了子类种,每一个子类负责创建一种具体的产品
特点:每个产品对应一个工厂类,符合开闭原则,新增产品只需要增加新的工厂类,无需修改现有代码。
使用场景:产品种类较多,且创建逻辑复杂的场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package factory_method
type Pay interface { PayPage(price int64) (string, error) }
type AliPay struct{}
func (p *AliPay) PayPage(price int64) (string, error) { return "aliPay", nil }
type WexinPay struct{}
func (p *WexinPay) PayPage(price int64) (string, error) { return "wexinPay", nil }
type PayType int8
const ( AliPayType = 1 WexinPayType = 2 )
type PayFactory interface { CreatePay() Pay }
type AliPayFactory struct{}
func (p *AliPayFactory) CreatePay() Pay { return &AliPay{} }
type WexinPayFactory struct{}
func (p *WexinPayFactory) CreatePay() Pay { return &WexinPay{} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package factory_method
import ( "fmt" "testing" )
func TestPayPage(t *testing.T) { aliPayFactory := AliPayFactory{} aliPay := aliPayFactory.CreatePay() fmt.Println(aliPay.PayPage(1))
wexinPayFactory := WexinPayFactory{} wexinPay := wexinPayFactory.CreatePay() fmt.Println(wexinPay.PayPage(1)) }
|
使用确实麻烦了,但是修改微信支付,不会影响到其他支付。扩展新的支付方式更容易。
创建型模式-抽象工厂模式
每个工厂类可以创建一组相关产品,强调产品族的概念。
使用场景:需要创建一组相关对象的场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| package abstract_method
import "fmt"
type Pay interface { PayPage(price int64) (string, error) }
type AliPay struct{}
func (p *AliPay) PayPage(price int64) (string, error) { return "aliPay", nil }
type WexinPay struct{}
func (p *WexinPay) PayPage(price int64) (string, error) { return "wexinPay", nil }
type PayType int8
const ( AliPayType = 1 WexinPayType = 2 )
type PayFactory interface { CreatePay() Pay CreateRefund() Refund }
type AliPayFactory struct{}
func (p *AliPayFactory) CreatePay() Pay { return &AliPay{} }
type WexinPayFactory struct{}
func (p *WexinPayFactory) CreatePay() Pay { return &WexinPay{} }
type Refund interface { Refund(orderNo string) error }
type AliRefund struct{}
func (p *AliRefund) Refund(orderNo string) error { fmt.Println("ali 退款") return nil }
type WexinRefund struct{}
func (p *WexinRefund) Refund(orderNo string) error { fmt.Println("wx 退款") return nil }
func (p *AliPayFactory) CreateRefund() Refund { return &AliRefund{}
}
func (p *WexinPayFactory) CreateRefund() Refund { return &WexinRefund{} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package abstract_method
import ( "fmt" "testing" )
func TestPayPage(t *testing.T) { aliPayFactory := AliPayFactory{} aliPay := aliPayFactory.CreatePay() fmt.Println(aliPay.PayPage(1)) aliPayFactory.CreateRefund().Refund("")
wexinPayFactory := WexinPayFactory{} wexinPay := wexinPayFactory.CreatePay() fmt.Println(wexinPay.PayPage(1)) wexinPayFactory.CreateRefund().Refund("") }
|
创建型模式-建造者模式
核心思想: 分步构建复杂对象。 将复杂对象的构建过程分离,分步。 体现单一职责
适用场景:
- 对象的构建过程复杂,包含多个步骤
- 对象构建过程需要支持不通的配置
比如要建立房子, 需要以下几个元素
房子:最终制品
建造规范:制定包工头需要符合的规范
包工头:按照建造规范建,交付房子
老板:告诉包工头建什么样的房子,获取房子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| package builder
import "fmt"
type House struct { Door string Window string }
type HouseBuilder interface { buildDoor(val string) buildWindow(val string) getHouse() *House }
type Bao struct { house *House }
func (b *Bao) getHouse() *House { return b.house }
func (b *Bao) buildDoor(val string) { b.house.Door = val fmt.Println("门建造成功") }
func (b *Bao) buildWindow(val string) { b.house.Window = val fmt.Println("窗户建造成功") }
func NewBao() *Bao { return &Bao{ house: &House{}, } }
type Boss struct { builder HouseBuilder }
func NewBoss(bao *Bao) *Boss { return &Boss{ builder: bao, } }
func (b *Boss) GetHouse() *House { b.builder.buildDoor("dor") b.builder.buildWindow("win") return b.builder.getHouse() }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package builder
import ( "fmt" "testing" )
func TestNewBao(t *testing.T) { b := NewBao() boss := NewBoss(b) fmt.Println(boss.GetHouse()) }
|
创建型模式-原型模式
通过复制现有对象来创建新对象,而不是通过新建类的方式。
避免重复初始化,特别适用于创建成本较高的对象。
局限:如果遇到应用类型,需要考虑深拷贝浅拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package prototype
type Prototype interface { Clone() Prototype }
type Student struct { Name string Age int }
func (s *Student) Clone() Prototype { return &Student{ Name: s.Name, Age: s.Age, } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package prototype
import ( "fmt" "testing" )
func TestStudent_Clone(t *testing.T) { s1 := Student{ Name: "xxx", Age: 18, } s2 := s1.Clone().(*Student) s2.Name = "yyyy" s2.Age = 111 fmt.Println(s1) fmt.Println(s2) }
|