抽象工厂模式
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂模式经常以工厂方法的方式实现。
模型说明
- 抽象产品(Abstract Product)为构成系列产品的一组不同但相关的产品声明接口。
- 具体产品(Concrete Product)是抽象产品的多种不同类型实现。 所有变体(维多利亚/现代)都必须实现相应的抽象产品(椅子/沙发)。
- 抽象工厂(Abstract Factory)接口声明了一组创建各种抽象产品的方法。
- 具体工厂(Concrete Factory)实现抽象工厂的构建方法。 每个具体工厂都对应特定产品变体, 且仅创建此种产品变体。
- 尽管具体工厂会对具体产品进行初始化,其构建方法签名必须返回相应的抽象产品。这样,使用工厂类的客户端代码就不会与工厂创建的特定产品变体耦合。客户端(Client)只需通过抽象接口调用工厂和产品对象,就能与任何具体工厂/产品变体交互。
优缺点
1.优点
- 你可以确保同一工厂生成的产品相互匹配。
- 你可以避免客户端和具体产品代码的耦合。
- *单一职责原则:*你可以将产品生成代码抽取到同一位置, 使得代码易于维护。
- *开闭原则:*向应用程序中引入新产品变体时, 你无需修改客户端代码。
2.缺点
- 由于采用该模式需要向应用中引入众多接口和类, 代码可能会比之前更加复杂。
使用场景
- 如果代码需要与多个不同系列的相关产品交互, 但是由于无法提前获取相关信息, 或者出于对未来扩展性的考虑, 你不希望代码基于产品的具体类进行构建, 在这种情况下, 你可以使用抽象工厂。
参考代码
在上篇文章的基础上,小米和华为都要生产手表的时候,我们应该怎么编码?
// factory.go // 抽象工厂,包含一系列创建产品的抽象 type IFactory interface { makePhone() IPhone makeWatch() IWatch } func GetFactory(tp string) IFactory { if tp == "xiaomi" { return &Xiaomi{} } else if tp == "huawei" { return &Huawei{} } else { panic("not found type") } return nil } // 具体工厂类 type Xiaomi struct{} func (x *Xiaomi) makePhone() IPhone { return &Phone{ name: "xiaomi 12", price: 3999, } } func (x *Xiaomi) makeWatch() IWatch { return &Watch{ name: "miWatch", price: 299, } } type Huawei struct{} func (h *Huawei) makePhone() IPhone { return &Phone{ name: "iPhone 14", price: 6999, } } func (h *Huawei) makeWatch() IWatch { return &Watch{ name: "apple watch", price: 2999, } }
// product.go // 抽象产品 type IPhone interface { setPhoneName(name string) setPhonePrice(price float64) getPhoneName() string getPhonePrice() float64 } type IWatch interface { setWatchName(name string) setWatchPrice(price float64) getWatchName() string getWatchPrice() float64 } // 具体产品类 type Phone struct { name string price float64 } func (g *Phone) setPhoneName(name string) { g.name = name } func (g *Phone) getPhoneName() string { return g.name } func (g *Phone) setPhonePrice(price float64) { g.price = price } func (g *Phone) getPhonePrice() float64 { return g.price } type Watch struct { name string price float64 } func (w *Watch) setWatchName(name string) { w.name = name } func (w *Watch) getWatchName() string { return w.name } func (w *Watch) setWatchPrice(price float64) { w.price = price } func (w *Watch) getWatchPrice() float64 { return w.price }
// main.go // 客户端调用 func main() { xiaomiFactory := GetFactory("xiaomi") xiaomiPhone := xiaomiFactory.makePhone() xiaomiWatch := xiaomiFactory.makeWatch() huaweiFactory := GetFactory("huawei") huaweiPhone := huaweiFactory.makePhone() huaweiWatch := huaweiFactory.makeWatch() printPhoneDetails(xiaomiPhone) printWatchDetails(xiaomiWatch) printPhoneDetails(huaweiPhone) printWatchDetails(huaweiWatch) } func printPhoneDetails(p IPhone) { fmt.Printf("Phone: %s", p.getPhoneName()) fmt.Println() fmt.Printf("Price: %.2f", p.getPhonePrice()) fmt.Println() fmt.Println("---------------------------") } func printWatchDetails(w IWatch) { fmt.Printf("watch: %s", w.getWatchName()) fmt.Println() fmt.Printf("Price: %.2f", w.getWatchPrice()) fmt.Println() fmt.Println("---------------------------") }
output:
Phone: xiaomi 12 Price: 3999.00 --------------------------- watch: miWatch Price: 299.00 --------------------------- Phone: iPhone 14 Price: 6999.00 --------------------------- watch: apple watch Price: 2999.00 ---------------------------