设计模式是经过验证,用于解决在特定环境下、重复出现、特定问题的解决方案。
github代码:
场景问题
例如有一个场景,有一个家具公司,提供椅子,桌子,沙发三类商品,有如下3个对象:
type Furniture interface {
get() Furniture
}
type chair struct {
}
type sofa struct {
}
type table struct {
}
func (chair) get() Furniture {
return chair{}
}
func (sofa) get() Furniture {
return sofa{}
}
func (table) get() Furniture {
return table{}
}
func shopping() {
// 如果客户想要椅子
chair := chair{}
chair.get()
// 如果客户想要沙发
sofa := sofa{}
sofa.get()
// 如果客户想要桌子
table := table{}
table.get()
}
使用者想要获取商品,还需要去调用不同的商品对应的get方法,这存在两个确定:
- 暴露太多细节:使用者不想知道每一个商品对应的生成方法,当系统复杂起来之后,不一定每一个商品的生成方法都是getXXX命名,这会让调用者花费更多时间在寻找get方法上。
- 复杂度:随着商品越来越多,客户想买的商品越来越多,可以想象到shopping类里面会出现越来越多,导致逻辑越来越复杂。
简单工厂
这时工厂模式的作用就出现了,稍微改动一下代码,增加一个工厂类:
type FurnitureFactor struct {}
func (FurnitureFactor) getFurniture(f string) Furniture {
if f == "chair" {
return chair{}
}
if f == "sofa" {
return sofa{}
}
if f == "table" {
return table{}
}
return nil
}
这下shopping的调用逻辑变为:
func Shopping() {
factor := FurnitureFactor{}
// 如果客户想要椅子
chair := factor.getFurniture("chair")
// 如果客户想要桌子
table := factor.getFurniture("table")
// 如果客户想要沙发
sofa := factor.getFurniture("sofa")
}
不在需要创建各种商品类,只需要用工厂类进行统一获取就可以了,这个工厂就是平时说的简单工厂。
抽象工厂
这时候工厂业务扩大,推出类不同的款式,例如推出木质和皮质两种材料的商品,新的商品类为:
type woodChair struct {
}
type woodSofa struct {
}
type woodTable struct {
}
func (woodChair) get() Furniture {
return woodChair{}
}
func (woodSofa) get() Furniture {
return woodSofa{}
}
func (woodTable) get() Furniture {
return woodTable{}
}
type leatherChair struct {
}
type leatherSofa struct {
}
type leatherTable struct {
}
func (leatherChair) get() Furniture {
return woodChair{}
}
func (leatherSofa) get() Furniture {
return woodSofa{}
}
func (leatherTable) get() Furniture {
return woodTable{}
}
所谓抽象工厂,就是普通工厂也利用接口的方式进行抽象出一个接口类型的工厂
// 工厂的抽象类
type FurnitureFactory interface {
getFurniture(f string) Furniture
}
// 制造木质商品的工厂
type WoodFactory struct {
}
func (WoodFactory) getFurniture(f string) Furniture {
if f == "chair" {
return woodChair{}
}
if f == "sofa" {
return woodSofa{}
}
if f == "table" {
return woodTable{}
}
return nil
}
// 制造皮质商品的工厂
type LeatherFactory struct {
}
func (LeatherFactory) getFurniture(f string) Furniture {
if f == "chair" {
return leatherChair{}
}
if f == "sofa" {
return leatherSofa{}
}
if f == "table" {
return leatherTable{}
}
return nil
}
这时候购物者可以这样来进行调用
func shopping() {
var wf FurnitureFactory = WoodFactory{}
wf.getFurniture("table")
wf.getFurniture("chair")
wf.getFurniture("sofa")
var lf FurnitureFactory = LeatherFactory{}
lf.getFurniture("table")
lf.getFurniture("chair")
lf.getFurniture("sofa")
}
简单工厂和抽象工厂模式的区别:
简单工厂的本质是选择实现,用来选择某一具体的实现。而抽象工厂是用来选择某一个类型的实现的,例如木制与皮制就是不同的类型。
如果当抽象工厂退化为只有一个实现,而且不分层次,那么就变成简单工厂了。
简单工厂的其他写法
静态工厂直接提供工厂的get方法,在java中是static修饰方法,在go中使用纯函数实现
// 静态工厂
func GetFurnitureStatic(f string) Furniture {
if f == "chair" {
return chair{}
}
if f == "sofa" {
return sofa{}
}
if f == "table" {
return table{}
}
return nil
}
带缓存的工厂 这适用于创建的对象可以进行共享,不会存在并发的风险。使用缓存可以节省对象重复创建的时间。
var CHAIR chair
var TABLE table
var SOFA sofa
// 带缓存的工厂
func (FurnitureFactor) getFurnitureCache(f string) Furniture {
if f == "chair" {
return CHAIR
}
if f == "sofa" {
return TABLE
}
if f == "table" {
return SOFA
}
return nil
}
参考引用:
- 《研磨设计模式》第二章
- refactoringguru.cn/design-patt…