文章目录
总共有22种设计模式,按照大类可分为:
行为模式:负责对象间的高效沟通和职责委派。
创建型模式:提供创建对象的机制, 能够提升已有代码的灵活性和可复用性。
结构型模式:介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效。
一、单例模式(创建型)
1、饿汉式
package hungry
type singleton struct {}
// 在包加载时, 就已经初始化了, 如果singleton结
// 构体很大,那么如果用不到就初始化了,非常浪费资源
var instance = &singleton{}
func GetInstance() *singleton {
return instance
}
2、懒汉式
package lazy
type singleton struct {}
var instance *singleton
// 在需要的时候才初始化, 避免浪费资源
func GetInstance() *singleton {
// 加锁是为了解决并发问题
m.Lock()
defer m.Unlock()
if instance == nil {
instance = &singleton{}
}
return instance
}
上面这样加锁是可以解决问题,但是太重了, 程序性能下降很严重。因此出现了下面的double checking lock。
3、双重检验锁(DCL)
package dcl
import "sync"
type singleton struct {}
var instance *singleton
var m sync.Mutex
func GetInstance() *singleton {
// 如果已经不为空就不进入加锁阶段了, 这样就优化了
if instance == nil {
m.Lock()
defer m.Unlock()
if instance == nil {
// jvm new对象, 分为下面三步(即三个cpu指令)
// 1. 给 instance 分配内存
// 2. 调用 Singleton 的构造函数来初始化成员变量
// 3. 将instance对象指向分配的内存空间(执行完这步 instance 就为非 null 了)
// 其中存在cpu指令重排、cpu cache的问题, 因此需要使用volatile修饰instance
// 这样就会使用主存, 而不是使用cpu cache, 避免了指令重排的尴尬
instance = &singleton{}
}
}
return instance
}
golang内存模型:https://blog.csdn.net/Zerore/article/details/120321985,这一块目前还不太清楚,大致看了下,我觉得golang中也是存在指令重排的,可以使用sync.once原子语言解决指令重排。
4、sync.once实现单例
package once
import "sync"
type singleton struct{}
var instance *singleton
var once sync.Once
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
二、工厂模式(创建型)
1、简单工厂模式
第一步:写产品(手机)的抽象接口
from abc import ABCMeta
class Phone(metaclass=ABCMeta):
def show(): pass
第二步: 对具体产品(华为手机与苹果手机)进行一个继承实现
class HuaWeiPhone(Phone):
def show():
print("Producing a Huawei phone!")
class ApplePhone(Phone):
def show():
print("Producing a Apple phone!")
第三步:产品(手机)的工厂类
class PhoneFactory():
@staticmethod
def createPhone(brand):
phone = None
if brand == "Apple":
phone = ApplePhone()
elif brand == "HuaWei":
phone = HuaWeiPhone()
else:
print("This phone brand not produce im my factory!")
return phone
弊端:违反了开闭原则
(对扩展是开放的,而对修改是封闭的),每次增加新产品(比如增加乘除法支持)都需要修改工厂类中的switch语句。违反了单一原则
,不管什么类(即不管什么品牌手机),都是在这一个工厂进行实例化,即苹果有苹果的工厂,华为有华为的工厂。
2、普通工厂模式
为了符合开闭原则、单一原则,于是诞生了普通工厂模式。这是对简单工厂模式的改进!
第一步:写产品(手机)的抽象接口
from abc import ABCMeta
class Phone(metaclass=ABCMeta):
def show(): pass
第二步: 对具体产品(华为手机与苹果手机)进行一个继承实现
class HuaWeiPhone(Phone):
def show():
print("Producing a Huawei phone!")
class ApplePhone(Phone):
def show():
print("Producing a Apple phone!")
我们可以发现,上面两步和简单工厂模式是一致的,只是下面这步不同。
第三步:产品(手机)的工厂类
class PhoneFactory(metaclass=ABCMeta):
def createPhone(): pass
class HuaWeiPhoneFactory(PhoneFactory):
def createPhone():
return HuaWeiPhone()
class ApplePhoneFactory(PhoneFactory):
def createPhone():
return ApplePhone()
客户端代码:
pf = HuaWeiPhoneFactory()
p = pf.createPhone()
p.show()
现在我们可以发现我们不会修改任何已存在的类,我们再加一个小米手机,也只需要加一个小米手机的实现和一个小米手机工厂的实现即可符合了开闭原则。而且一个工厂生产的都是一个品牌的手机,符合了单一原则。
3、抽象工厂模式
普通工厂模式只是符合品牌的产品结构单一的情况使用
,即华为只有手机。然而现实中,华为不仅有手机,还有华为平板、华为电脑等。有人可能会说,这不就不单一了吗?不是的,单一指的是品牌(产品簇)单一
,而不是产品单一。为了解决这个问题,就出现了抽象工厂模式:
第一步:写产品(手机、平板)的抽象接口
from abc import ABCMeta
class Phone(metaclass=ABCMeta):
def show(): pass
class Pad(metaclass=ABCMeta):
def show(): pass
第二步: 对具体产品(华为手机、平板与苹果手机、平板)进行一个继承实现
class HuaWeiPhone(Phone):
def show():
print("Producing a Huawei phone!")
class ApplePhone(Phone):
def show():
print("Producing a Apple phone!")
class HuaWeiPad(Pad):
def show():
print("Producing a Huawei pad!")
class ApplePad(Pad):
def show():
print("Producing a Apple pad!")
第三步:产品(手机、平板)的工厂类
class PhoneFactory(metaclass=ABCMeta):
def createPad(): pass
def createPhone(): pass
class HuaWeiPhoneFactory(PhoneFactory):
def createPhone():
return HuaWeiPhone()
def createPad():
return HuaWeiPad()
class ApplePhoneFactory(PhoneFactory):
def createPhone():
return ApplePhone()
def createPad():
return ApplePad()
其实我们可以发现抽象工厂模式只是比普通模式工厂多了个抽象方法而已. 算是对普通工厂模式的一种升级
三、装饰模式(结构型)
注意:下面在装饰器中所做操作,都是使用了这个装饰器类去装饰对象,才拥有的额外的东西,它并没有对对象本身的类做任何修改
.
package decorate
import "fmt"
type Roboter interface {
DoSomething()
}
type FirstRobot struct {}
func (fr *FirstRobot) DoSomething() {
fmt.Println("第一代机器人只会扫地、拖地、放音乐")
}
type robotDecorator struct {
// 可以给被装饰对象加属性, 即给机器人加衣服、裤子等
robot Roboter
}
func NewRobotDecorator(robot Roboter) *robotDecorator {
robotDecorator := &robotDecorator{}
robotDecorator.robot = robot
return robotDecorator
}
// 也可以给被装饰对象添加一些方法, 即增加机器人的其他干活功能. 你当然可以
// 选择在装饰类中修改原有的DoSomething, 或者使用被装饰对象的DoSomething
func (rd *robotDecorator) DoSomething() {
// fmt.Println("第一代机器人啥都不会干了")
rd.robot.DoSomething() // 使用被装饰对象原有的DoSomething
}
func (rd *robotDecorator) DoMoreThing() {
fmt.Println("你现在还会做饭,洗衣服,照顾孩子")
}
客户端代码:
package main
import (
"design-mode/decorate"
)
func main() {
firstRobot := &decorate.FirstRobot{}
robotDecorator := decorate.NewRobotDecorator(firstRobot)
robotDecorator.DoMoreThing()
}