面向对象创建型模式(go语言)

本文详细介绍了四种常见的设计模式:单例模式确保类只有一个实例并提供全局访问点,节省资源;饿汉和懒汉模式作为单例的实现方式,分别在类装载时和首次使用时创建实例;工厂模式通过工厂方法创建对象,简化对象创建过程;抽象工厂模式则为创建相关对象家族提供统一接口。此外,还探讨了原型模式用于高效复制对象,以及建造者模式逐步构建复杂对象。这些模式在实际编程中有着广泛应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点,主要解决一个全局使用的类频繁的创建和销毁,节省内存的开销,避免对资源的多重占用。没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外部怎么实例化的。关键代码构造函数私有化,外部不能随意创建,但是Go语言没这种,private、public。那就用大小写来代替是否对外暴露

大家都要喝水,但是没必要每人家里都打一口井,通常的做法是整个村里打一个井就够了,大家都从这个井里面打水喝。

  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。
  • 3、单例类必须给所有其他对象提供这一实例。

饿汉模式

提前实例化好对象,等待直接调用就行。

优点:写法简单,在类装载时完成实例化,没有加锁,执行效率会提高,避免了线程同步问题。

缺点:类装载时完成实例化,没有达到懒加载的效果,若该实例从未使用,则会造成内存浪费。

func main() {
	sing1 := GetInstance()
	sing1.SingFunc()
    
    sing2 := GetInstance()
	fmt.Printf("sing1:%p\tsing2:%p", sing1, sing2)
}
// 小写代表private,对外暴露GetInstance获取实例
var instance *singleton = new(singleton)

type singleton struct {
}

func GetInstance() *singleton {
	return instance
}
func (receiver singleton) SingFunc() {
	fmt.Println("饿汉式的方法。。。")
}
/*
饿汉式的方法。。。
sing1:0x660458	sing2:0x660458

懒汉模式

饿汉式可能造成资源浪费,所以就有了懒汉式,先不创建类的对象实例,等需要的时候再创建。

线程不安全:懒加载,没有加锁,所以线程不安全,多线程下不能正常工作。

线程安全:懒加载,能够在多线程中工作,但是加锁效率降低

func main() {
	sing1 := GetInstance()
	sing1.SingFunc()

	sing2 := GetInstance()
	fmt.Printf("sing1:%p\tsing2:%p", sing1, sing2)
}
// 小写代表private,对外暴露GetInstance获取实例
var instance *singleton

type singleton struct {
}

func GetInstance() *singleton {
	if instance == nil {
		instance = new(singleton)
	}
	return instance
}
func (receiver singleton) SingFunc() {
	fmt.Println("懒汉式的线程不安全方法。。。")
}
/*
懒汉式的线程不安全方法。。。
sing1:0xa80438	sing2:0xa80438
func main() {
	sing1 := GetInstance()
	sing1.SingFunc()

	sing2 := GetInstance()
	fmt.Printf("sing1:%p\tsing2:%p", sing1, sing2)
}
// 小写代表private,对外暴露GetInstance获取实例
var instance *singleton
var lock sync.Mutex
var initialized uint32

type singleton struct {
}

func GetInstance() *singleton {
	// 标记位
	if atomic.LoadUint32(&initialized) == 1 {
		return instance
	}

	lock.Lock()
	defer lock.Unlock()
	if instance == nil {
		instance = new(singleton)
		atomic.StoreUint32(&initialized, 1)
	}
	return instance
}
func (receiver singleton) SingFunc() {
	fmt.Println("懒汉式的线程安全方法。。。")
}
/*
懒汉式的线程安全方法。。。
sing1:0xc50460	sing2:0xc50460

添加标记位的目的就是减少加锁的次数,多线程时每次调用这个方法都要加锁判断效率会很低。

Go语言还有一种新的方法,就是 once,内容只执行一次,这样就简化了加锁实例

func main() {
	sing1 := GetInstance()
	sing1.SingFunc()

	sing2 := GetInstance()
	fmt.Printf("sing1:%p\tsing2:%p", sing1, sing2)
}
// 小写代表private,对外暴露GetInstance获取实例
var instance *singleton
var once sync.Once

type singleton struct {
}

func GetInstance() *singleton {
	once.Do(func() {
		instance = new(singleton)
	})
	return instance
}
func (receiver singleton) SingFunc() {
	fmt.Println("懒汉式的线程安全方法。。。")
}
/*
懒汉式的线程安全方法。。。
sing1:0xc70458	sing2:0xc70458

工厂模式

简单工厂模式

在这里插入图片描述

func main() {
	fruitfactory := FruitFactory{}
	apple := fruitfactory.CreatFruit("apple")
	apple.show()
	pear := fruitfactory.CreatFruit("pear")
	pear.show()
}

type FruitFactory struct {
}
type apple struct {
}
type pear struct {
}
type Fruit interface {
	show()
}

func (receiver apple) show() {
	fmt.Println("苹果。。。")
}
func (receiver pear) show() {
	fmt.Println("梨子。。。")
}
func (receiver FruitFactory) CreatFruit(fruit string) Fruit {
	switch fruit {
	case "apple":
		return apple{}
	case "pear":
		return pear{}
	}
	return nil
}
/*
苹果。。。
梨子。。。

工厂方法模式

请添加图片描述

func main() {
	applefactory := new(appleFactory)
	apple := applefactory.CreatFruit()
	apple.Show()

	var pearfactory FruitFactory
	pearfactory = new(pearFactory)
	pear := pearfactory.CreatFruit()
	pear.Show()
}

type FruitFactory interface {
	CreatFruit() Fruit
}
type Fruit interface {
	Show()
}
type appleFactory struct {
}
type pearFactory struct {
}

type apple struct {
}
func (receiver apple) Show() {
	fmt.Println("苹果。。。。")
}

type pear struct {
}
func (receiver pear) Show() {
	fmt.Println("梨子。。。。")
}

func (receiver appleFactory) CreatFruit() Fruit {
	return apple{}
}
func (receiver pearFactory) CreatFruit() Fruit {
	return pear{}
}
/*
苹果。。。。
梨子。。。。

抽象工厂模式

请添加图片描述
请添加图片描述

func main() {
	var chinaFactory Factory
	chinaFactory = new(ChinaFactory)
	chinaApple := chinaFactory.CreatApple()
	chinaApple.show()

	usaFactory := USAFactory{}
	usaPear := usaFactory.CreatPear()
	usaPear.show()
}

// 抽象层
type Factory interface {
	CreatApple() Apple
	CreatPear() Pear
}
type Apple interface {
	show()
}
type Pear interface {
	show()
}

// 中国工厂
type ChinaFactory struct {
}
type ChinaApple struct {
}
type ChinaPear struct {
}

func (receiver ChinaFactory) CreatApple() Apple {
	return ChinaApple{}
}
func (receiver ChinaFactory) CreatPear() Pear {
	return ChinaPear{}
}
func (receiver ChinaApple) show() {
	fmt.Println("中国的苹果。。。")
}
func (receiver ChinaPear) show() {
	fmt.Println("中国的梨子。。。")
}

// 美国工厂
type USAFactory struct {
}
type USAApple struct {
}
type USAPear struct {
}

func (receiver USAFactory) CreatApple() Apple {
	return USAApple{}
}
func (receiver USAFactory) CreatPear() Pear {
	return USAPear{}
}
func (receiver USAApple) show() {
	fmt.Println("美国的苹果。。。")
}
func (receiver USAPear) show() {
	fmt.Println("美国的梨子。。。")
}
/*
中国的苹果。。。
美国的梨子。。。

原型模式

用于创建重复的对象,同时又能保证性能,当直接创建对象的代价比较大时,则采用这种模式。一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

浅拷贝、深拷贝

请添加图片描述

func main() {
	Manager = NewCellsManager()
	细胞1 := &Cell{
		ID: 1,
	}
	fmt.Printf("细胞1:%p\n", 细胞1)

	Manager.Set("标号1", 细胞1)
	fmt.Printf("缓存中的细胞1:%p\n", Manager.Get("标号1"))

	细胞2 := Manager.Get("标号1").Clone()
	fmt.Printf("细胞2:%p\n", 细胞2)
}

var Manager *CellsManager

type CloneCache interface {
	Clone() CloneCache
}
type Cell struct {
	ID uint32
}
func (receiver *Cell) Clone() CloneCache {
	cloneCell := *receiver
	return &cloneCell
}


type CellsManager struct {
	cloneCache map[string]CloneCache
}
func NewCellsManager() *CellsManager {
	return &CellsManager{
		cloneCache: make(map[string]CloneCache),
	}
}
func (receiver *CellsManager) Set(name string, cloneCache CloneCache) {
	receiver.cloneCache[name] = cloneCache
}
func (receiver *CellsManager) Get(name string) CloneCache {
	return receiver.cloneCache[name]
}
/*
细胞1:0xc00000a098
缓存中的细胞1:0xc00000a098
细胞2:0xc00000a0cc

细胞2和细胞1的地址不同,也说明是从Cache中拷贝出来的新对象

建造者模式

使用多个简单的对象一步一步构建成一个复杂的对象,一个 Builder 类一步一步构造最终的对象,该 Builder 类是独立于其他对象的。

面临着一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。将变与不变的分离开。

请添加图片描述

func main() {
	mealBuilder = NewMealBuilder()
	张三 := Meal{
		Items: make(map[string]Item),
		sum:   0,
	}
	张三.AddItem("蔬菜汉堡", mealBuilder.BurgerMeal.vegBurger)
	张三.AddItem("可乐", mealBuilder.DrinkMeal.cock)
	张三.AddItem("鸡肉汉堡", mealBuilder.BurgerMeal.chickenBurger)
	张三.AddItem("果汁", mealBuilder.DrinkMeal.juice)
	张三.ShowItems()
	张三.GetSum()
	fmt.Println("一共花费:", 张三.sum, "元")
}

var mealBuilder *MealBuilder

type Item interface {
	GetPrice() float64
}
type VegBurger struct {
}
type ChickenBurger struct {
}
type Coke struct {
}
type Juice struct {
}

func (receiver VegBurger) GetPrice() float64 {
	return 8.0
}
func (receiver ChickenBurger) GetPrice() float64 {
	return 10.0
}
func (receiver Coke) GetPrice() float64 {
	return 5.8
}
func (receiver Juice) GetPrice() float64 {
	return 4.3
}

type Burger struct {
	vegBurger     VegBurger
	chickenBurger ChickenBurger
}
type Drink struct {
	cock  Coke
	juice Juice
}

type Meal struct {
	Items map[string]Item
	sum   float64
}

func (receiver *Meal) AddItem(name string, item Item) {
	receiver.Items[name] = item
}
func (receiver *Meal) GetSum() {
	receiver.sum = 0
	for _, item := range receiver.Items {
		receiver.sum += item.GetPrice()
	}
}
func (receiver *Meal) ShowItems() {
	fmt.Println("--- 账单 ---")
	for name, item := range receiver.Items {
		fmt.Println(name, ":", item.GetPrice(), "元")
	}
	fmt.Println("------------")
}

type MealBuilder struct {
	BurgerMeal *Burger
	DrinkMeal  *Drink
}
func NewMealBuilder() *MealBuilder {
	return &MealBuilder{
		BurgerMeal: new(Burger),
		DrinkMeal:  new(Drink),
	}
}
/*
--- 账单 ---
果汁 : 4.3 元
蔬菜汉堡 : 8 元
可乐 : 5.8 元
鸡肉汉堡 : 10 元
------------
一共花费: 28.1 元
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

paidx0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值