创建型模式:Singleton、Builder、Factory Method、Abstract Factory、Prototype
Singleton 单例设计模式
having a unique instance of a type in the entire program
在整个程序中只具有某一类型的唯一实例
示例:唯一的计数器
package creational
type singleton struct {
count int
}
var instance *singleton
func GetInstance() *singleton {
if instance == nil {
instance = new(singleton)
}
return new(singleton)
}
func (s *singleton) AddOne() int {
s.count++
return s.count
}
测例 go test -v ./patterns/creational -cover
package creational
import (
"testing"
)
func Test_singleton_AddOne(t *testing.T) {
c1 := GetInstance()
currentCount := c1.AddOne()
if currentCount != 1 {
t.Errorf("After calling for the first time to count, the count must be1 but it is %d\n", currentCount)
}
c2 := GetInstance()
currentCount = c2.AddOne()
if currentCount != 2 {
t.Errorf("After calling 'AddOne' using the second counter, the currentcount must be 2 but was %d\n", currentCount)
}
}
func TestGetInstance(t *testing.T) {
c1 := GetInstance()
c2 := GetInstance()
if c1 == nil || c2 == nil {
t.Errorf("expected pointer to Singleton after calling GetInstance(), not nil")
}
if c1 != c2 {
t.Errorf("Expected same instance in counter2 but it got a different instance")
}
}
Builder 建造者设计模式
reusing an algorithm to create many implementations of an interface
重用某个算法来创建接口的多个实现
例如,你将使用几乎相同的技术来建造一辆汽车,你将建造一辆公共汽车,除了他们将不同的大小和座位的数量,所以我们为什么不重复建造过程(组装结构,放置车轮,放置座椅)?
示例:车辆制造
核心思想:ManufacturingDirector负责重用建造过程
package creational
//产品接口,开放更改
type VehicleProduct struct {
Wheels int
Seats int
Structure string
}
//定义一组车辆建造的行为
type BuildProcess interface {
SetWheels() BuildProcess
SetSeats() BuildProcess
SetStructure() BuildProcess
Build() VehicleProduct
}
//----------导演
type ManufacturingDirector struct {
bp BuildProcess
}
//使用BuildProcess进行产品构造
func (f *ManufacturingDirector) Construct() {
//Implementation goes here
f.bp.SetSeats().SetWheels().SetStructure()
}
func (f *ManufacturingDirector) SetBuilder(b BuildProcess) {
//Implementation goes here
f.bp = b
}
//----------小车建造器
type CarBuilder struct {
v VehicleProduct
}
func (c *CarBuilder) SetWheels() BuildProcess {
c.v.Wheels = 4
return c
}
func (c *CarBuilder) SetSeats() BuildProcess {
c.v.Seats = 5
return c
}
func (c *CarBuilder) SetStructure() BuildProcess {
c.v.Structure = "Car"
return c
}
func (c *CarBuilder) Build() VehicleProduct { return c.v }
//--------摩托车建造器
type BikeBuilder struct {
v VehicleProduct
}
func (b *BikeBuilder) SetWheels() BuildProcess {
b.v.Wheels = 2
return b
}
func (b *BikeBuilder) SetSeats() BuildProcess {
b.v.Seats = 2
return b
}
func (b *BikeBuilder) SetStructure() BuildProcess {
b.v.Structure = "Motorbike"
return b
}
func (b *BikeBuilder) Build() VehicleProduct { return b.v }
测例
package creational
import "testing"
func TestBuilderPattern(t *testing.T) {
manufacturingComplex := ManufacturingDirector{}
carBuilder := &CarBuilder{}
manufacturingComplex.SetBuilder(carBuilder)
manufacturingComplex.Construct()
car := carBuilder.Build()
if car.Wheels != 4 {
t.Errorf("Wheels on a car must be 4 and they were %d\n", car.Wheels)
}
if car.Structure != "Car" {
t.Errorf("Structure on a car must be 'Car' and was %s\n", car.Structure)
}
if car.Seats != 5 {
t.Errorf("Seats on a car must be 5 and they were %d\n", car.Seats)
}
bikeBuilder := &BikeBuilder{}
manufacturingComplex.SetBuilder(bikeBuilder)
manufacturingComplex.Construct()
motorbike := bikeBuilder.Build()
motorbike.Seats = 1 //开放更改测试
if motorbike.Wheels != 2 {
t.Errorf("Wheels on a motorbike must be 2 and they were %d\n", motorbike.Wheels)
}
if motorbike.Structure != "Motorbike" {
t.Errorf("Structure on a motorbike must be 'Motorbike' and was %s\n", motorbike.Structure)
}
}
如果想建造Bus,只需加一个BusBuilder即可。
Builder设计模式通过director总监使用的通用构造算法,帮助我们维护不可预知的产品数量。构造过程通常是从产品的用户中抽象出来的。
但是, 当您不能完全确定算法是否会更稳定时,请尽量避免使用Builder模式,因为此接口中的任何小变化都会影响到所有的构建器,如果您添加了一些构建器需要而其他构建器不需要的新方法,可能会很尴尬。
Factory method 工厂方法
delegating the creation of different types of payments
代理不同类型的创建
例子:商店付款方式的工厂方法
package creational
import (
"errors"
"fmt"
)
const (
Cash = 1
DebitCard = 2
)
type PaymentMethod interface {
Pay(amount float32) string
}
type CashPM struct{}
func (c CashPM) Pay(amount float32) string {
return fmt.Sprintf("%0.2f paid using cash\n", amount)
}
type DebitCardPM struct{}
func (c DebitCardPM) Pay(amount float32) string {
return fmt.Sprintf("%#0.2f paid using debit card\n", amount)
}
//工厂方法
func GetPaymentMethod(m int) (PaymentMethod, error) {
switch m {
case Cash:
return new(CashPM), nil
case DebitCard:
return new(DebitCardPM), nil //修改成CreditCardPM,完成升级
default:
return nil, errors.New(fmt.Sprintf("Payment method %d notrecognized\n", m))
}
}
//------将升级DebitCardPM,替换为新的付款方式(或新增),只需添加一个实现
type CreditCardPM struct{}
func (d *CreditCardPM) Pay(amount float32) string {
return fmt.Sprintf("%#0.2f paid using new credit card implementation\n", amount)
}
测例 go test -v ./patterns/creational -cover
package creational
import (
"strings"
"testing"
)
func TestGetPaymentMethodCash(t *testing.T) {
pm, err := GetPaymentMethod(Cash)
if err != nil {
t.Fatal("A payment method of type 'Cash' must exist")
}
msg := pm.Pay(4.3)
if !strings.Contains(msg, "paid using cash") {
t.Error("The cash payment method message wasn't correct")
}
t.Log("LOG:", msg)
}
func TestGetPaymentMethodDebitCard(t *testing.T) {
pm, err := GetPaymentMethod(DebitCard)
if err != nil {
t.Fatal("A payment method of type 'DebitCard' must exist")
}
msg := pm.Pay(3.3)
if !strings.Contains(msg, "paid using debit card") {
t.Error("The debit card payment method message wasn't correct")
}
t.Log("LOG:", msg)
}
func TestGetPaymentMethodNonExistent(t *testing.T) {
_, err := GetPaymentMethod(20)
if err == nil {
t.Error("A payment method with ID 20 must return an error")
}
t.Log("LOG:", err)
}
Abstract Factory 抽象工厂
a factory of factories
抽象工厂设计模式是一个新的分组层,用于实现更大(更复杂)的复合对象,通过其接口使用。当你的对象数量越来越多,以至于创建一个独特的点来获得所有的对象时,将相关的对象家族分组是非常方便的,这似乎是获得运行时对象创建灵活性的唯一方法。目标如下:
- 为Factory方法提供一个新的封装层,它为所有工厂返回一个通用接口
- 将普通工厂分组成一个超级工厂(也称工厂中的工厂)
示例:车辆建造(car簇,motorbike簇),由于类型非常多,将分割成多个go文件
//---vehicle.go
package abstractfactory
type Vehicle interface {
NumWheels() int
NumSeats() int
}
//----vehicle_factory.go
package abstractfactory
import (
"errors"
"fmt"
)
//工厂的工厂,每一种工厂需要实现此接口
type VehicleFactory interface {
Build(v int) (Vehicle, error)
}
const (
CarFactoryType = 1
MotorbikeFactoryType = 2
)
//建造工厂(抽象工厂方法)
func BuildFactory(f int) (VehicleFactory, error) {
switch f {
default:
return nil, errors.New(fmt.Sprintf("Factory with id %d not recognized\n", f))
}
}
//-------
const (
LuxuryCarType = 1
FamilyCarType = 2
)
type CarFactory struct {
}
func (c *CarFactory) Build(v int) (Vehicle, error) {
switch v {
case LuxuryCarType:
return new(LuxuryCar), nil
case FamilyCarType:
return new(FamilyCar), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
//-------
const (
SportMotorbikeType = 1
CruiseMotorbikeType = 2
)
type MotorbikeFactory struct{}
func (c *MotorbikeFactory) Build(v int) (Vehicle, error) {
switch v {
case SportMotorbikeType:
return new(SportMotorbike), nil
case CruiseMotorbikeType:
return new(CruiseMotorbike), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
//---car.go
package abstractfactory
import (
"errors"
"fmt"
)
//工厂的工厂,每一种工厂需要实现此接口
type VehicleFactory interface {
Build(v int) (Vehicle, error)
}
const (
CarFactoryType = 1
MotorbikeFactoryType = 2
)
//建造工厂(抽象工厂方法)
func BuildFactory(f int) (VehicleFactory, error) {
switch f {
default:
return nil, errors.New(fmt.Sprintf("Factory with id %d not recognized\n", f))
}
}
//-------
const (
LuxuryCarType = 1
FamilyCarType = 2
)
type CarFactory struct {
}
func (c *CarFactory) Build(v int) (Vehicle, error) {
switch v {
case LuxuryCarType:
return new(LuxuryCar), nil
case FamilyCarType:
return new(FamilyCar), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
//-------
const (
SportMotorbikeType = 1
CruiseMotorbikeType = 2
)
type MotorbikeFactory struct{}
func (c *MotorbikeFactory) Build(v int) (Vehicle, error) {
switch v {
case SportMotorbikeType:
return new(SportMotorbike), nil
case CruiseMotorbikeType:
return new(CruiseMotorbike), nil
default:
return nil, errors.New(fmt.Sprintf("Vehicle of type %d not recognized\n", v))
}
}
//-----motorbike.go
package abstractfactory
//An interface for motorbikes of the types sport (oneseat) and cruise (two seats).
type Motorbike interface {
GetMotorbikeType() int
}
//-------
type SportMotorbike struct{}
func (s *SportMotorbike) GetMotorbikeType() int { return SportMotorbikeType }
func (s *SportMotorbike) NumWheels() int { return 2 }
func (s *SportMotorbike) NumSeats() int { return 1 }
//-------
type CruiseMotorbike struct{}
func (c *CruiseMotorbike) GetMotorbikeType() int { return CruiseMotorbikeType }
func (c *CruiseMotorbike) NumWheels() int { return 2 }
func (c *CruiseMotorbike) NumSeats() int { return 2 }
测例 go test -v ./patterns/creational/abstract_factory -cover
package abstractfactory
import (
"testing"
)
func TestMotorbikeFactory(t *testing.T) {
motorbikeF, err := BuildFactory(MotorbikeFactoryType)
if err != nil {
t.Fatal(err)
}
motorbikeVehicle, err := motorbikeF.Build(SportMotorbikeType)
if err != nil {
t.Fatal(err)
}
t.Logf("Motorbike vehicle has %d wheels\n", motorbikeVehicle.NumWheels())
//motorbikeVehicle是vehicle接口,无法直接使用motorbike接口的方法,需要使用断言,返回目标类型
sportBike, ok := motorbikeVehicle.(Motorbike)
if !ok {
t.Fatal("Struct assertion has failed")
}
t.Logf("Sport motorbike has type %d\n", sportBike.GetMotorbikeType())
}
func TestCarFactory(t *testing.T) {
carF, err := BuildFactory(CarFactoryType)
if err != nil {
t.Fatal(err)
}
carVehicle, err := carF.Build(LuxuryCarType)
if err != nil {
t.Fatal(err)
}
t.Logf("Car vehicle has %d seats\n", carVehicle.NumWheels())
luxuryCar, ok := carVehicle.(Car)
if !ok {
t.Fatal("Struct assertion has failed")
}
t.Logf("Luxury car has %d doors.\n", luxuryCar.NumDoors())
}
Prototype 原型设计模式
Prototype模式的目标是拥有一个或一组在编译时已经创建的对象,但您可以在运行时任意复制这些对象。这种模式和Builder模式的关键区别在于,对象是为用户克隆的,而不是在运行时构建它们。
Prototype设计模式的主要目标是避免重复创建对象,它是构建缓存和默认对象的强大工具。
示例:衬衫定制
package creational
import (
"errors"
"fmt"
)
//----不同类型的衬衫(白色,黑色,蓝色分别为15,16和17美元
type ShirtCloner interface {
GetClone(s int) (ItemInfoGetter, error)
}
func GetShirtCloner() ShirtCloner {
return &ShirtCache{}
}
//cloner实例
type ShirtCache struct{}
func (sc *ShirtCache) GetClone(s int) (ItemInfoGetter, error) {
switch s {
case White:
//newItem := *whitePrototype
return whitePrototype, nil
case Black:
newItem := *blackPrototype
return &newItem, nil
case Blue:
newItem := *blackPrototype
return &newItem, nil
default:
return nil, errors.New("Shirt model not recognized")
}
}
//-----
type ItemInfoGetter interface {
GetInfo() string
}
//三种颜色
const (
White = 1
Black = 2
Blue = 3
)
type ShirtColor byte
type Shirt struct {
Price float32
SKU string
Color ShirtColor
}
func (s *Shirt) GetInfo() string {
return fmt.Sprintf("Shirt with SKU '%s' and Color id %d that costs %f\n", s.SKU, s.Color, s.Price)
}
func (s *Shirt) GetPrice() float32 { return s.Price }
var whitePrototype *Shirt = &Shirt{Price: 15.00, SKU: "empty", Color: White}
var blackPrototype *Shirt = &Shirt{Price: 16.00, SKU: "empty", Color: Black}
var bluePrototype *Shirt = &Shirt{Price: 17.00, SKU: "empty", Color: Blue}
测例
package creational
import "testing"
//验收标准:
//要求不同类型的衬衫(白色,黑色,蓝色分别为15.00,16.00和17.00美元)
//当您要求一件白衬衫时,必须制作一件白衬衫的克隆,并且新实例必须与原实例不同
//创建对象的SKU不应该影响新对象的创建
//info方法必须为我提供实例字段上可用的所有信息,包括更新后的SKU
func TestPrototype(t *testing.T) {
shirtCache := GetShirtCloner()
if shirtCache == nil {
t.Fatal("Received cache was nil")
}
item1, err := shirtCache.GetClone(White)
if err != nil {
t.Error(err)
}
if item1 == whitePrototype {
t.Error("item1 cannot be equal to the white prototype")
}
//检验SKU
shirt1, ok := item1.(*Shirt)
if !ok {
t.Fatal("Type assertion for shirt1 couldn't be done successfully")
}
shirt1.SKU = "abbcc"
item2, err := shirtCache.GetClone(White)
if err != nil {
t.Fatal(err)
}
shirt2, ok := item2.(*Shirt)
if !ok {
t.Fatal("Type assertion for shirt2 couldn't be done successfully")
}
if shirt1.SKU == shirt2.SKU {
t.Error("SKU's of shirt1 and shirt2 must be different")
}
if shirt1 == shirt2 {
t.Error("Shirt 1 cannot be equal to Shirt 2")
}
//检验info
t.Logf("LOG: %s", shirt1.GetInfo())
t.Logf("LOG: %s", shirt2.GetInfo())
t.Logf("LOG: The memory positions of the shirts are different %p != %p\n\n", &shirt1, &shirt2)
}
本文介绍了Go(Golang)语言中的五种创建型设计模式:Singleton、Builder、Factory Method、Abstract Factory和Prototype。Singleton确保了程序中只有一个实例;Builder模式用于构建复杂对象,允许分离对象的构建过程和表示;Factory Method将对象的创建委托给子类;Abstract Factory则提供了一组工厂来创建相关对象家族;Prototype模式允许在运行时复制已有对象,减少创建新对象的开销。每个模式都配有示例和测试用例。

6954

被折叠的 条评论
为什么被折叠?



