设计模式-创建型-go实现版
介绍
在软件开发中,创建型设计模式(Creational Design Pattern)是一组用于对象创建的设计模式。它们的共同目标是封装对象的创建过程,从而提高代码的复用性和灵活性。根据经典的GOF设计模式,创建型模式主要包括以下5种:
工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法模式让一个类的实例化延迟到其子类中进行。
抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。
建造者模式(Builder Pattern):将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
原型模式(Prototype Pattern):使用原型实例指定创建对象的种类,并通过复制这些原型来创建新的对象。
除了这五种经典的创建型设计模式,还有一些变体或衍生的创建型模式,例如简单工厂模式、多例模式等。每种创建型模式都有其特定的适用场景和优缺点,开发者需要根据实际情况选择最适合自己项目需求的模式。
使用场景
创建型设计模式是用于创建对象的一种模式。常见的创建型设计模式有以下几种:
工厂方法模式:定义一个用于创建对象的接口,但由子类决定要实例化的类是哪一个,适用于需要动态地创建对象的场景。
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,适用于需要创建一系列相关对象的场景。
单例模式:确保一个类只有一个实例,并提供全局访问点,适用于需要确保只有一个实例存在的场景。
原型模式:通过复制已有对象来创建新对象,而无需知道任何创建的细节,适用于需要快速创建新对象的场景。
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,适用于需要创建复杂对象的场景。
在选择创建型设计模式时,需要考虑以下几个方面:
系统的复杂性:如果系统非常复杂,那么可能需要使用创建型设计模式来帮助管理对象的创建和组织。
对象的数量:如果需要创建大量的对象,那么可以考虑使用创建型设计模式来减少对象的创建和销毁次数。
对象的依赖关系:如果对象之间存在复杂的依赖关系,那么可以考虑使用创建型设计模式来处理这些依赖关系。
系统的扩展性:选择合适的创建型设计模式可以使系统更易于扩展和维护。
总之,在选择创建型设计模式时,需要结合自己的经验和技能,综合考虑各种因素,以选择最适合自己的设计模式。同时,还需要注意不要过度使用设计模式,以免代码过于复杂。
实现例子
工厂方法模式
工厂方法模式是一种常用的创建型设计模式,它的核心思想是将对象的创建过程封装起来,使得对象的创建和使用相分离。在 Go 语言中,可以通过接口和结构体实现工厂方法模式。
package main
import "fmt"
// 定义接口
type Product interface {
GetName() string
}
// 定义结构体A
type ProductA struct{}
func (p *ProductA) GetName() string {
return "ProductA"
}
// 定义结构体B
type ProductB struct{}
func (p *ProductB) GetName() string {
return "ProductB"
}
// 定义工厂接口
type Factory interface {
Create() Product
}
// 定义工厂A
type FactoryA struct{}
func (f *FactoryA) Create() Product {
return &ProductA{}
}
// 定义工厂B
type FactoryB struct{}
func (f *FactoryB) Create() Product {
return &ProductB{}
}
func main() {
// 创建工厂A
factoryA := &FactoryA{}
// 通过工厂A创建产品A
productA := factoryA.Create()
fmt.Println(productA.GetName()) // 输出:ProductA
// 创建工厂B
factoryB := &FactoryB{}
// 通过工厂B创建产品B
productB := factoryB.Create()
fmt.Println(productB.GetName()) // 输出:ProductB
}
在这个示例中,Product
接口定义了产品的方法,ProductA
和 ProductB
结构体分别实现了 Product
接口。Factory
接口定义了工厂的方法,FactoryA
和 FactoryB
结构体分别实现了 Factory
接口,其中 FactoryA
可以用于创建 ProductA
,FactoryB
可以用于创建 ProductB
。
在 main
函数中,我们创建了 FactoryA
和 FactoryB
两个工厂,然后通过它们分别创建了 ProductA
和 ProductB
两个产品。由于每个工厂只能创建对应的产品,因此输出的结果也不同。
抽象工厂模式
抽象工厂模式是一种创建型设计模式,它提供了一个创建一系列相关或依赖对象的接口,而无需指定具体类。在 Go 语言中,可以通过接口和结构体实现抽象工厂模式。
package main
import "fmt"
// 定义接口1
type Button interface {
Paint()
}
// 定义接口2
type Label interface {
Paint()
}
// 定义工厂接口
type GUIFactory interface {
CreateButton() Button
CreateLabel() Label
}
// 定义具体按钮结构体
type WindowsButton struct{}
func (b *WindowsButton) Paint() {
fmt.Println("Windows Button")
}
type MacButton struct{}
func (b *MacButton) Paint() {
fmt.Println("Mac Button")
}
// 定义具体标签结构体
type WindowsLabel struct{}
func (l *WindowsLabel) Paint() {
fmt.Println("Windows Label")
}
type MacLabel struct{}
func (l *MacLabel) Paint() {
fmt.Println("Mac Label")
}
// 定义具体工厂
type WindowsGUIFactory struct{}
func (f *WindowsGUIFactory) CreateButton() Button {
return &WindowsButton{}
}
func (f *WindowsGUIFactory) CreateLabel() Label {
return &WindowsLabel{}
}
type MacGUIFactory struct{}
func (f *MacGUIFactory) CreateButton() Button {
return &MacButton{}
}
func (f *MacGUIFactory) CreateLabel() Label {
return &MacLabel{}
}
func main() {
// 创建Windows GUI工厂
windowsFactory := &WindowsGUIFactory{}
windowsButton := windowsFactory.CreateButton()
windowsLabel := windowsFactory.CreateLabel()
windowsButton.Paint() // 输出:Windows Button
windowsLabel.Paint() // 输出:Windows Label
// 创建Mac GUI工厂
macFactory := &MacGUIFactory{}
macButton := macFactory.CreateButton()
macLabel := macFactory.CreateLabel()
macButton.Paint() // 输出:Mac Button
macLabel.Paint() // 输出:Mac Label
}
单例模式
在 Go 语言中,可以通过 sync 包的 Once 类型实现单例模式。Once 类型可以保证其内部的函数只会执行一次,因此我们可以利用它来实现单例模式。
package singleton
import "sync"
type singleton struct{}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
在上面的代码中,我们首先定义了一个名为 singleton 的结构体类型,用来表示单例对象。然后定义了一个全局变量 instance,用来存储单例对象的实例。同时,我们还定义了一个 sync.Once 类型的全局变量 once,用来保证 GetInstance 函数只会执行一次。
GetInstance 函数会首先判断 instance 是否已经被初始化。如果已经被初始化,直接返回 instance;否则,执行 once.Do 函数来初始化 instance,并返回 instance。
使用 sync.Once 实现单例模式的好处在于它可以保证线程安全,并且只会在第一次使用时才会初始化单例对象。这样可以避免在程序启动时就初始化单例对象,从而提高程序启动速度。
建造者模式
在 Go 语言中,可以通过建造者模式来创建复杂的对象。建造者模式将对象的创建过程分解为多个简单的步骤,从而使得不同的创建过程可以组合在一起,生成不同的对象。
package builder
type Builder interface {
SetName(name string) Builder
SetAge(age int) Builder
Build() *Person
}
type Person struct {
Name string
Age int
}
type PersonBuilder struct {
person *Person
}
func NewPersonBuilder() *PersonBuilder {
return &PersonBuilder{person: &Person{}}
}
func (b *PersonBuilder) SetName(name string) Builder {
b.person.Name = name
return b
}
func (b *PersonBuilder) SetAge(age int) Builder {
b.person.Age = age
return b
}
func (b *PersonBuilder) Build() *Person {
return b.person
}
在上面的代码中,我们定义了一个 Builder 接口,用来描述建造者模式的创建过程。Builder 接口中包含了多个简单的方法,用来设置不同的属性。同时,我们还定义了一个 Person 结构体,用来表示最终生成的对象。
PersonBuilder 结构体实现了 Builder 接口,并包含了一个指向 Person 结构体的指针。在 SetName 和 SetAge 方法中,我们设置了 Person 结构体的 Name 和 Age 属性,并返回了 PersonBuilder 的指针,用于链式调用。在 Build 方法中,我们返回了 Person 结构体的指针,表示创建过程结束。
使用建造者模式可以将复杂对象的创建过程分解为多个简单的步骤,从而使得创建过程更加灵活和可扩展。在上面的示例中,我们只需要在 PersonBuilder 结构体中添加更多的方法来设置其他属性,就可以创建不同的 Person 对象。
原型模式
原型模式是一种创建型设计模式,其主要思想是通过克隆现有对象来创建新的对象,从而避免使用昂贵的构造函数。在 Go 语言中,可以通过接口和结构体来实现原型模式。
package prototype
import (
"fmt"
)
type Prototype interface {
Clone() Prototype
GetName() string
}
type ConcretePrototype struct {
name string
}
func (p *ConcretePrototype) Clone() Prototype {
return &ConcretePrototype{name: p.name}
}
func (p *ConcretePrototype) GetName() string {
return p.name
}
func main() {
prototype := &ConcretePrototype{name: "prototype"}
clone := prototype.Clone()
fmt.Println(clone.GetName())
}
在上面的代码中,我们定义了一个 Prototype 接口,其中包含了 Clone 和 GetName 两个方法。Clone 方法用于克隆对象,GetName 方法用于获取对象的名称。同时,我们还定义了一个 ConcretePrototype 结构体,用于表示具体的原型对象。在 Clone 方法中,我们通过创建一个新的 ConcretePrototype 对象来克隆原型对象。在 GetName 方法中,我们返回了原型对象的名称。
在 main 函数中,我们首先创建了一个 ConcretePrototype 对象,然后通过调用 Clone 方法来克隆该对象。最后,我们打印了克隆对象的名称,证明克隆操作成功。
使用原型模式可以避免使用昂贵的构造函数,从而提高对象创建的效率。另外,原型模式还可以用来动态生成对象,具有很好的扩展性。
其他
结构型设计模式-golang实现
mp.weixin.qq.com/s?__biz=Mzg2ODcxM...
行为型设计模式-golang实现
mp.weixin.qq.com/s?__biz=Mzg2ODcxM...
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: