抽象工厂模式(创建型模式)
模式概述
抽象工厂是一种创建型设计模式,它能够创建一系列相关的对象而无需指定具体类。
这个定义和工厂方法模式很像,但其实是不同的。
问题
假设公司目前正在研发一款穿搭风格模拟器,代码中有这样一些类。
一些列相关的产品,如上衣、长裤和手提包。
不同年龄段的消费者,如女大学生,职业女性和老年妇女。
就像这样(形状代表模特,仅为示意😄)。

消费者需要根据不同的搭配生成自己喜爱的风格。
而且,如果今后有更多风格样式,程序员也肯定不希望去修改已有代码。
方案
抽象工厂模式为系列中的每件产品都提供了明确的接口,例如上衣、长裤和包包,同时包含多个创建产品的方法。
并且确保所有不同风格的产品都实现这些接口。例如不管是女大学生、职业女性还是老年妇女,她们穿的上衣,都必须实现上衣
接口,依此类推。

接下来,通过声明抽象工厂中所有产品构造方法的接口来创建抽象产品:

对于系列产品的每个不同变体,都将通过抽象工厂接口创建不同的工厂类,所以每个工厂类只能返回特定类别的产品。例如女大学生工厂只能生产女大学生的上衣、女大学生长裤和女大学生包包。
客户端代码无需了解具体工厂的信息,就可以通过抽象接口调用不同的工厂和产品类。
一般情况下,客户端只和抽象接口有关联,而具体的工厂对象一般是由应用环境上下文根据预先的配置完成初始化的。
结构

实现
Java
/**
* 上衣产品接口
*
*/
public interface Clothes {
void hasSleeve();
}
/**
* 女大学生上衣产品
*
*/
public class StudentClothes implements Clothes {
@Override
public void hasSleeve() {
System.out.println("创建了女大学生上衣");
}
}
/**
* 职业女性上衣产品
*
*/
public class CareerClothes implements Clothes {
@Override
public void hasSleeve() {
System.out.println("创建了职业女性上衣");
}
}
/**
* 长裤产品接口
*
*/
public interface Pants {
void hasButton();
}
/**
* 女大学生长裤产品
*
*/
public class StudentPants implements Pants {
@Override
public void hasButton() {
System.out.println("创建了女大学生长裤");
}
}
/**
* 职业女性长裤产品
*
*/
public class CareerPants implements Pants {
@Override
public void hasButton() {
System.out.println("创建了职业女性长裤");
}
}
/**
* 抽象工厂
*
*/
public interface StyleFactory {
Clothes createClothes();
Pants createPants();
}
/**
* 女大学生抽象工厂
*
*/
public class StudentStyleFactory implements StyleFactory {
@Override
public Clothes createClothes() {
return new StudentClothes();
}
@Override
public Pants createPants() {
return new StudentPants();
}
}
/**
* 职业女性抽象工厂
*
*/
public class CareerStyleFactory implements StyleFactory {
@Override
public Clothes createClothes() {
return new CareerClothes();
}
@Override
public Pants createPants() {
return new CareerPants();
}
}
/**
* 客户端
*
*/
public class Client {
private Clothes clothes;
private Pants pants;
public Client(StyleFactory factory) {
clothes = factory.createClothes();
pants = factory.createPants();
}
public void paint() {
clothes.hasSleeve();
pants.hasButton();
}
}
/**
* 上下文配置,初始化抽象工厂模式的运行环境
*
*/
public class Application {
private static Client configureApplication() {
Client client;
StyleFactory factory;
String product = System.getProperty("products").toLowerCase();
if (product.contains("student")) {
factory = new StudentStyleFactory();
} else {
factory = new CareerStyleFactory();
}
client = new Client(factory);
return client;
}
public static void main(String[] args) {
Client client = configureApplication();
client.paint();
}
}
Go
package main
import "fmt"
/**
* 抽象工厂接口
*
*/
type ISportsFactory interface {
makeShoe() IShoe
makeShirt() IShirt
}
func GetSportsFactory(brand string) (ISportsFactory, error) {
if brand == "adidas" {
return &Adidas{}, nil
}
if brand == "nike" {
return &Nike{}, nil
}
return nil, fmt.Errorf("错误的品牌类型")
}
/**
* Adidas具体工厂
*
*/
type Adidas struct {
}
func (adidas *Adidas) makeShoe() IShoe {
return &AdidasShoe{
Shoe: Shoe{
logo: "adidas",
size: 14,
},
}
}
func (adidas *Adidas) makeShirt() IShirt {
return &AdidasShirt{
Shirt: Shirt{
logo: "adidas",
size: 14,
},
}
}
/**
* Nike具体工厂
*
*/
type Nike struct {
}
func (nike *Nike) makeShoe() IShoe {
return &NikeShoe{
Shoe: Shoe{
logo: "nike",
size: 14,
},
}
}
func (nike *Nike) makeShirt() IShirt {
return &NikeShirt{
Shirt: Shirt{
logo: "nike",
size: 14,
},
}
}
/**
* iShoe抽象产品
*
*/
type IShoe interface {
setLogo(logo string)
setSize(size int)
getLogo() string
getSize() int
}
type Shoe struct {
logo string
size int
}
func (s *Shoe) setLogo(logo string) {
s.logo = logo
}
func (s *Shoe) getLogo() string {
return s.logo
}
func (s *Shoe) setSize(size int) {
s.size = size
}
func (s *Shoe) getSize() int {
return s.size
}
/**
* AdidasShoe具体产品
*
*/
type AdidasShoe struct {
Shoe
}
/**
* NikeShoe具体产品
*
*/
type NikeShoe struct {
Shoe
}
/**
* iShirt抽象产品
*
*/
type IShirt interface {
setLogo(logo string)
setSize(size int)
getLogo() string
getSize() int
}
type Shirt struct {
logo string
size int
}
func (s *Shirt) setLogo(logo string) {
s.logo = logo
}
func (s *Shirt) getLogo() string {
return s.logo
}
func (s *Shirt) setSize(size int) {
s.size = size
}
func (s *Shirt) getSize() int {
return s.size
}
/**
* AdidasShirt具体产品
*
*/
type AdidasShirt struct {
Shirt
}
/**
* NikeShirt具体产品
*
*/
type NikeShirt struct {
Shirt
}
/**
* 客户端代码
*
*/
func main() {
adidasFactory, _ := GetSportsFactory("adidas")
nikeFactory, _ := GetSportsFactory("nike")
nikeShoe := nikeFactory.makeShoe()
nikeShirt := nikeFactory.makeShirt()
adidasShoe := adidasFactory.makeShoe()
adidasShirt := adidasFactory.makeShirt()
printShoeDetails(nikeShoe)
printShirtDetails(nikeShirt)
printShoeDetails(adidasShoe)
printShirtDetails(adidasShirt)
}
func printShoeDetails(s IShoe) {
fmt.Printf("Logo:%s", s.getLogo())
fmt.Println()
fmt.Printf("Size:%d", s.getSize())
fmt.Println()
}
func printShirtDetails(s IShirt) {
fmt.Printf("Logo:%s", s.getLogo())
fmt.Println()
fmt.Printf("Size:%d", s.getSize())
fmt.Println()
}
适用场景
当系统中存在有多个产品族,而每次只使用其中某一产品族。
需要创建多个不同系列的产品,但无法提前获取产品相关信息。
优缺点
抽象工厂模式的优点。
抽象工厂模式隔离了具体产品的生成,实现了具体产品与客户端的解耦。
当引入新的事先定义的产品族时,无需修改代码,符合
开闭原则
。当多个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
抽象工厂模式的缺点。
- 难以扩展抽象工厂来生产新种类的产品,因为这意味着所有的具体工厂和具体产品都要被修改。例如,如果需要增加一款女士长裙产品,就难以修改。
相关性
抽象工厂模式
可以生产一系列的相关对象,并会马上返回产品;而构建器模式
则允许在创建产品前执行一些额外配置步骤。当需要对客户端隐藏子系统创建对象的方式时,可以使用
抽象工厂模式
来代替外观模式
。如果由
桥接模式
定义的抽象只与特定实现合作,那么抽象工厂模式
可以对这些关系进行封装,并且对客户端代码隐藏其复杂性。工厂方法模式
可以演化为抽象工厂模式
、原型模式
和构建器
模式。抽象工厂模式
、构建器模式
和原型模式
都可以用单例模式
来实现。
感谢支持
更多内容,请移步《超级个体》。