【创造型模式】抽象工厂方法模式

文章目录

抽象工厂方法模式

工厂方法模式引入了"工厂等级结构",解决了简单工厂方法过分依赖单一工厂的问题。但是工厂方法模式存在的一个问题是,针对每一种产品,都需要设计一种工厂,比如对于"苹果"和"山东苹果",我们就需要分别设计一个"苹果工厂"和"山东苹果工厂"。

工厂方法模式现有的问题在于:

  1. 但添加一个新产品的时候(比如葡萄),虽然遵循开闭原则,不修改现有的代码,但是需要添加大量的类(比如辽宁葡萄、河北葡萄、山东葡萄),而且需要添加相对应的工厂,增加了系统开销和维护成本。
  2. 如果同一个"地域"有多种产品,比如"辽宁葡萄"、"辽宁樱桃"、"辽宁苹果",那么需要分别创建具体的工厂,而不能通过一个工厂来生产所有的产品。虽然该方法满足开闭原则,但是代码将会变得非常复杂,不够好。

抽象工厂方法模式的引入进一步优化了工厂方法模式。具体来说,抽象工厂方法模式引入了"产品等级结构"和"产品族"这两个概念。

产品族与产品等级结构

此处借用《Easy 搞定 Golang 设计模式》当中的原图:

  • 产品族:具有同一个地区、同一个厂商、同一个开发包、同一个组织模块等隶属关系,但是具备不同的特点或功能,这样的产品构成的集合,就是一个产品族。比如产自同一个产地的各种水果,就构成一个产品族。
  • 产品等级结构:具有相同特点或功能,但是隶属的组织模块不同,这样的产品结构,称为一个产品等级。不同产地的同一种水果就是同一个产品等级。

"抽象工厂方法模式"针对"产品族"进行产品生产。

抽象工厂方法模式的角色和职责

  • 抽象工厂角色:声明了一组用于创建一组产品的方法 ,每一个方法对应一种产品。
  • 具体工厂角色:实现了在抽象工厂中声明的创建产品的方法,生成一组具体的产品,这些产品构成一个产品族,每一个产品都位于某个产品结构当中。
  • 抽象产品角色:为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
  • 具体产品角色:定义具体工厂生产的具体产品对象,实现抽象产品接口声明的业务方法。

抽象工厂方法模式的实现

go 复制代码
package main

import "fmt"

// ---------- 抽象层 ----------
type AbstractApple interface {
	ShowApple()
}

type AbstractBanana interface {
	ShowBanana()
}

type AbstractPear interface {
	ShowPear()
}

// 抽象工厂: 定义了工厂可以生产哪些抽象产品
type AbstractFactory interface {
	CreateApple() AbstractApple
	CreateBanana() AbstractBanana
	CreatePear() AbstractPear
}

// ---------- 实现层 ----------
type LiaoningApple struct{}

func (la *LiaoningApple) ShowApple() {
	fmt.Println("Liaoning Apple")
}

type LiaoningBanana struct{}

func (lb *LiaoningBanana) ShowBanana() {
	fmt.Println("Liaoning Banana")
}

type LiaoningPear struct{}

func (lp *LiaoningPear) ShowPear() {
	fmt.Println("Liaoning Pear")
}

type LiaoningFactory struct{}

func (fa *LiaoningFactory) CreateApple() AbstractApple {
	return &LiaoningApple{}
}

func (fa *LiaoningFactory) CreateBanana() AbstractBanana {
	return &LiaoningBanana{}
}

func (fa *LiaoningFactory) CreatePear() AbstractPear {
	return &LiaoningPear{}
}

type JiangsuApple struct{}

func (ja *JiangsuApple) ShowApple() {
	fmt.Println("Jiangsu Apple")
}

type JiangsuBanana struct{}

func (jb *JiangsuBanana) ShowBanana() {
	fmt.Println("Jiangsu Banana")
}

type JiangsuPear struct{}

func (jp *JiangsuPear) ShowPear() {
	fmt.Println("Jiangsu Pear")
}

type JiangsuFactory struct{}

func (fa *JiangsuFactory) CreateApple() AbstractApple {
	return &JiangsuApple{}
}

func (fa *JiangsuFactory) CreateBanana() AbstractBanana {
	return &JiangsuBanana{}
}

func (fa *JiangsuFactory) CreatePear() AbstractPear {
	return &JiangsuPear{}
}

type BeijingApple struct{}

func (ba *BeijingApple) ShowApple() {
	fmt.Println("Beijing Apple")
}

type BeijingBanana struct{}

func (bb *BeijingBanana) ShowBanana() {
	fmt.Println("Beijing Banana")
}

type BeijingPear struct{}

func (pbp *BeijingPear) ShowPear() {
	fmt.Println("Beijing Pear")
}

type BeijingFactory struct{}

func (fa *BeijingFactory) CreateApple() AbstractApple {
	return &BeijingApple{}
}

func (fa *BeijingFactory) CreateBanana() AbstractBanana {
	return &BeijingBanana{}
}

func (fa *BeijingFactory) CreatePear() AbstractPear {
	return &BeijingPear{}
}

func main() {
	// 创建辽宁的苹果, 香蕉, 梨等对象
	var liaoningFac AbstractFactory
	liaoningFac = &LiaoningFactory{}

	var liaoningApple AbstractApple
	liaoningApple = liaoningFac.CreateApple()
	liaoningApple.ShowApple()

	var liaoningBanana AbstractBanana
	liaoningBanana = liaoningFac.CreateBanana()
	liaoningBanana.ShowBanana()

	var liaoningPear AbstractPear
	liaoningPear = liaoningFac.CreatePear()
	liaoningPear.ShowPear()

	// 创建其他产区的水果
	jiangsuFac := &JiangsuFactory{}

	jiangsuApple := jiangsuFac.CreateApple()
	jiangsuApple.ShowApple()

	jiangsuBanana := jiangsuFac.CreateBanana()
	jiangsuBanana.ShowBanana()

	jiangsuPear := jiangsuFac.CreatePear()
	jiangsuPear.ShowPear()

	beijingFac := &BeijingFactory{}

	beijingApple := beijingFac.CreateApple()
	beijingApple.ShowApple()

	beijingBanana := beijingFac.CreateBanana()
	beijingBanana.ShowBanana()

	beijingPear := beijingFac.CreatePear()
	beijingPear.ShowPear()
}

抽象工厂方法模式的优缺点

优点:

  • 继承了工厂方法模式的优点;
  • 确保客户端始终只使用一个同产品族中的对象;
  • 增加新的产品族很方便,对于上例而言,可以直接设计一个新的工厂并实现抽象工厂的接口。

缺点:

  • 新增产品的等级结构复杂,需要对原有系统进行较大的修改,甚至可能修改抽象层的代码。

适用场景

  • 系统中有多于一个产品族,每次只使用某个产品族。
  • 产品等级结构问题,设计系统完成后,不会向系统中新增产品等级结构或删除已有的产品等级结构。
相关推荐
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式
咖啡八杯1 天前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法
咖啡八杯2 天前
GoF设计模式——解释器模式
java·后端·spring·设计模式