抽象工厂模式(Abstract Factory)基于工厂方法模式。两者的区别在于:工厂方法模式是创建出一种产品,而抽象工厂模式是创建出一类产品。这二种都属于工厂模式,在设计上是相似的。
抽象工厂模式和工厂方法不太一样,它要解决的问题比较复杂,不但工厂是抽象的,产品是抽象的,而且有多个产品需要创建,因此,这个抽象工厂会对应到多个实际工厂,每个实际工厂负责创建多个实际产品。
抽象工厂模式适合应用场景:
- 如果代码需要与多个不同系列的相关实体交互,但是由于无法提前获取相关信息,或者出于对未来扩展性的考虑,你不希望代码基于实体的具体类进行构建,在这种情况下,你可以使用抽象工厂。
- 如果你有一个基于一组抽象方法的类, 且其主要功能因此变得不明确, 那么在这种情况下可以考虑使用抽象工厂模式。
问题
假设,有一个文章存储工厂,提供 Redis 和 MySQL 两种存储数据的方式。使用工厂方法模式,我们就需要一个文章存储工厂,并提供 Redis 和 MySQL 的存储方法。
如果此时业务还需要分成存储散文和古诗两种载体,这两种载体都可以进行 Redis 和 MySQL 存储。就可以使用抽象工厂模式,我们需要一个存储工厂作为父工厂,散文工厂和古诗工厂作为子工厂,并提供对应的保存方法。
解决
以上文的存储工厂业务为例,用抽象工厂模式的思路来设计代码,就像下面这样:
package main
import "fmt"
// StorageFactory 抽象存储工厂
type StorageFactory interface {
CreateProse() Prose // 生产抽象散文产品
CreatePoetry() Poetry // 生产抽象古诗产品
}
// 抽象散文产品
type Prose interface {
Save()
}
// 抽象古诗产品
type Poetry interface {
Save()
}
// 具体 redis 散文产品
type RedisProse struct{}
func (*RedisProse) Save() {
fmt.Println("Redis Save Prose")
}
// 具体 redis 古诗产品
type RedisPoetry struct{}
func (*RedisPoetry) Save() {
fmt.Println("Redis Save Poetry")
}
// 具体 mysql 散文产品
type MySQLProse struct{}
func (*MySQLProse) Save() {
fmt.Println("MySQL Save Prose")
}
// 具体 mysql 古诗产品
type MySQLPoetry struct{}
func (*MySQLPoetry) Save() {
fmt.Println("MySQL Save Poetry")
}
// 具体 redis 存储工厂
type RedisFactory struct{}
func (*RedisFactory) CreateProse() Prose {
return &RedisProse{}
}
func (*RedisFactory) CreatePoetry() Poetry {
return &RedisPoetry{}
}
// 实现 mysql 存储工厂
type MySQLFactory struct{}
func (*MySQLFactory) CreateProse() Prose {
return &MySQLProse{}
}
func (*MySQLFactory) CreatePoetry() Poetry {
return &MySQLPoetry{}
}
func Save(storageFactory StorageFactory) {
storageFactory.CreateProse().Save()
storageFactory.CreatePoetry().Save()
}
func main() {
var factory StorageFactory
factory = &RedisFactory{}
Save(factory)
factory = &MySQLFactory{}
Save(factory)
}
参考文章: