简单工厂&抽象工厂

325 阅读3分钟

设计模式是经过验证,用于解决在特定环境下、重复出现、特定问题的解决方案。

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方法,这存在两个确定:

  1. 暴露太多细节:使用者不想知道每一个商品对应的生成方法,当系统复杂起来之后,不一定每一个商品的生成方法都是getXXX命名,这会让调用者花费更多时间在寻找get方法上。
  2. 复杂度:随着商品越来越多,客户想买的商品越来越多,可以想象到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
}

参考引用:

  1. 《研磨设计模式》第二章
  2. refactoringguru.cn/design-patt…