抽象工厂模式详解:概念、实现与应用
引言
抽象工厂模式是创建型设计模式中的一个重要模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式是工厂方法模式的进一步扩展,它关注的是产品族的创建,而不是单一产品的创建。
什么是抽象工厂模式?
抽象工厂模式是一种创建型设计模式,它能创建一系列相关的对象,而无需指定其具体类。抽象工厂模式关注的是产品族的概念,一个产品族是一组相关或相互依赖的产品。
核心思想
抽象工厂模式的核心思想是:
- 产品族概念:一组相关或相互依赖的产品
- 接口抽象:定义创建产品族的接口
- 具体实现:具体工厂实现接口,创建具体产品族
为什么需要抽象工厂模式?
在许多情况下,我们需要创建一组相关的产品对象:
1. 产品族一致性
当需要确保一组相关的产品对象一起使用时:
- UI 组件的风格一致性(Windows 风格、Mac 风格)
- 数据库访问的一致性(连接、命令、适配器等)
- 游戏中的角色装备一致性
2. 系统平台兼容性
当系统需要支持多个平台时:
- 不同操作系统的 UI 组件
- 不同数据库的访问组件
- 不同设备的驱动程序
3. 产品配置管理
当需要管理复杂的产品配置时:
- 产品族的版本管理
- 产品族的兼容性检查
- 产品族的替换和升级
抽象工厂模式的基本实现
让我们从一个简单的抽象工厂模式实现开始:
javascript
// 抽象产品 A
class AbstractProductA {
operationA() {
throw new Error('必须实现 operationA 方法');
}
}
// 抽象产品 B
class AbstractProductB {
operationB() {
throw new Error('必须实现 operationB 方法');
}
anotherOperationB(collaborator) {
throw new Error('必须实现 anotherOperationB 方法');
}
}
// 具体产品 A1
class ConcreteProductA1 extends AbstractProductA {
operationA() {
return 'ConcreteProductA1 的结果';
}
}
// 具体产品 A2
class ConcreteProductA2 extends AbstractProductA {
operationA() {
return 'ConcreteProductA2 的结果';
}
}
// 具体产品 B1
class ConcreteProductB1 extends AbstractProductB {
operationB() {
return 'ConcreteProductB1 的结果';
}
anotherOperationB(collaborator) {
const result = collaborator.operationA();
return `ConcreteProductB1 与 (${result}) 协作`;
}
}
// 具体产品 B2
class ConcreteProductB2 extends AbstractProductB {
operationB() {
return 'ConcreteProductB2 的结果';
}
anotherOperationB(collaborator) {
const result = collaborator.operationA();
return `ConcreteProductB2 与 (${result}) 协作`;
}
}
// 抽象工厂
class AbstractFactory {
createProductA() {
throw new Error('必须实现 createProductA 方法');
}
createProductB() {
throw new Error('必须实现 createProductB 方法');
}
}
// 具体工厂 1
class ConcreteFactory1 extends AbstractFactory {
createProductA() {
return new ConcreteProductA1();
}
createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂 2
class ConcreteFactory2 extends AbstractFactory {
createProductA() {
return new ConcreteProductA2();
}
createProductB() {
return new ConcreteProductB2();
}
}
// 客户端代码
function clientCode(factory) {
const productA = factory.createProductA();
const productB = factory.createProductB();
console.log(productB.operationB());
console.log(productB.anotherOperationB(productA));
}
// 使用具体工厂 1
console.log('客户端:使用 ConcreteFactory1 的产品族');
clientCode(new ConcreteFactory1());
console.log('');
// 使用具体工厂 2
console.log('客户端:使用 ConcreteFactory2 的产品族');
clientCode(new ConcreteFactory2());实现要点分析
- 产品族结构:定义多个产品接口和具体产品实现
- 工厂接口:定义创建产品族的接口
- 具体工厂:实现工厂接口,创建具体产品族
- 产品协作:产品之间可以相互协作
抽象工厂模式的实际应用场景
1. 跨平台 UI 组件库
在开发跨平台应用程序时,抽象工厂模式非常适合用于创建不同平台的 UI 组件:
javascript
// UI 组件抽象接口
class Button {
render() {
throw new Error('必须实现 render 方法');
}
}
class Checkbox {
render() {
throw new Error('必须实现 render 方法');
}
check() {
throw new Error('必须实现 check 方法');
}
}
// Windows 风格组件
class WindowsButton extends Button {
render() {
return '<button class="windows-button">Windows 按钮</button>';
}
}
class WindowsCheckbox extends Checkbox {
render() {
return '<input type="checkbox" class="windows-checkbox" />';
}
check() {
return 'Windows 复选框被选中';
}
}
// Mac 风格组件
class MacButton extends Button {
render() {
return '<button class="mac-button">Mac 按钮</button>';
}
}
class MacCheckbox extends Checkbox {
render() {
return '<input type="checkbox" class="mac-checkbox" />';
}
check() {
return 'Mac 复选框被选中';
}
}
// UI 工厂抽象接口
class GUIFactory {
createButton() {
throw new Error('必须实现 createButton 方法');
}
createCheckbox() {
throw new Error('必须实现 createCheckbox 方法');
}
}
// Windows 工厂
class WindowsFactory extends GUIFactory {
createButton() {
return new WindowsButton();
}
createCheckbox() {
return new WindowsCheckbox();
}
}
// Mac 工厂
class MacFactory extends GUIFactory {
createButton() {
return new MacButton();
}
createCheckbox() {
return new MacCheckbox();
}
}
// 应用程序类
class Application {
constructor(factory) {
this.factory = factory;
this.button = null;
this.checkbox = null;
}
createUI() {
this.button = this.factory.createButton();
this.checkbox = this.factory.createCheckbox();
}
render() {
if (!this.button || !this.checkbox) {
throw new Error('UI 未创建');
}
return {
button: this.button.render(),
checkbox: this.checkbox.render()
};
}
handleCheckboxClick() {
if (!this.checkbox) {
throw new Error('复选框未创建');
}
return this.checkbox.check();
}
}
// 使用示例
function createApplication(platform) {
let factory;
switch (platform) {
case 'windows':
factory = new WindowsFactory();
break;
case 'mac':
factory = new MacFactory();
break;
default:
throw new Error(`不支持的平台: ${platform}`);
}
const app = new Application(factory);
app.createUI();
return app;
}
// Windows 应用
const windowsApp = createApplication('windows');
console.log('Windows 应用 UI:', windowsApp.render());
console.log(windowsApp.handleCheckboxClick());
// Mac 应用
const macApp = createApplication('mac');
console.log('Mac 应用 UI:', macApp.render());
console.log(macApp.handleCheckboxClick());2. 数据库访问组件族
在企业级应用中,抽象工厂模式可以用于创建不同数据库的访问组件:
javascript
// 数据库连接接口
class Connection {
connect() {
throw new Error('必须实现 connect 方法');
}
close() {
throw new Error('必须实现 close 方法');
}
}
// 命令接口
class Command {
execute(sql) {
throw new Error('必须实现 execute 方法');
}
}
// 数据适配器接口
class DataAdapter {
fetch(query) {
throw new Error('必须实现 fetch 方法');
}
save(data) {
throw new Error('必须实现 save 方法');
}
}
// MySQL 组件
class MySQLConnection extends Connection {
connect() {
return '连接到 MySQL 数据库';
}
close() {
return '关闭 MySQL 连接';
}
}
class MySQLCommand extends Command {
execute(sql) {
return `在 MySQL 中执行 SQL: ${sql}`;
}
}
class MySQLDataAdapter extends DataAdapter {
fetch(query) {
return `MySQL 获取数据: ${query}`;
}
save(data) {
return `MySQL 保存数据: ${JSON.stringify(data)}`;
}
}
// PostgreSQL 组件
class PostgreSQLConnection extends Connection {
connect() {
return '连接到 PostgreSQL 数据库';
}
close() {
return '关闭 PostgreSQL 连接';
}
}
class PostgreSQLCommand extends Command {
execute(sql) {
return `在 PostgreSQL 中执行 SQL: ${sql}`;
}
}
class PostgreSQLDataAdapter extends DataAdapter {
fetch(query) {
return `PostgreSQL 获取数据: ${query}`;
}
save(data) {
return `PostgreSQL 保存数据: ${JSON.stringify(data)}`;
}
}
// 数据库工厂接口
class DatabaseFactory {
createConnection() {
throw new Error('必须实现 createConnection 方法');
}
createCommand() {
throw new Error('必须实现 createCommand 方法');
}
createDataAdapter() {
throw new Error('必须实现 createDataAdapter 方法');
}
}
// MySQL 工厂
class MySQLFactory extends DatabaseFactory {
createConnection() {
return new MySQLConnection();
}
createCommand() {
return new MySQLCommand();
}
createDataAdapter() {
return new MySQLDataAdapter();
}
}
// PostgreSQL 工厂
class PostgreSQLFactory extends DatabaseFactory {
createConnection() {
return new PostgreSQLConnection();
}
createCommand() {
return new PostgreSQLCommand();
}
createDataAdapter() {
return new PostgreSQLDataAdapter();
}
}
// 数据访问上下文
class DatabaseContext {
constructor(factory) {
this.factory = factory;
this.connection = null;
this.command = null;
this.dataAdapter = null;
}
initialize() {
this.connection = this.factory.createConnection();
this.command = this.factory.createCommand();
this.dataAdapter = this.factory.createDataAdapter();
}
connect() {
if (!this.connection) {
throw new Error('数据库上下文未初始化');
}
return this.connection.connect();
}
executeSQL(sql) {
if (!this.command) {
throw new Error('数据库上下文未初始化');
}
return this.command.execute(sql);
}
fetchData(query) {
if (!this.dataAdapter) {
throw new Error('数据库上下文未初始化');
}
return this.dataAdapter.fetch(query);
}
saveData(data) {
if (!this.dataAdapter) {
throw new Error('数据库上下文未初始化');
}
return this.dataAdapter.save(data);
}
disconnect() {
if (this.connection) {
return this.connection.close();
}
}
}
// 使用示例
function createDatabaseContext(dbType) {
let factory;
switch (dbType) {
case 'mysql':
factory = new MySQLFactory();
break;
case 'postgresql':
factory = new PostgreSQLFactory();
break;
default:
throw new Error(`不支持的数据库类型: ${dbType}`);
}
const context = new DatabaseContext(factory);
context.initialize();
return context;
}
// MySQL 使用示例
const mysqlContext = createDatabaseContext('mysql');
console.log(mysqlContext.connect());
console.log(mysqlContext.executeSQL('SELECT * FROM users'));
console.log(mysqlContext.fetchData('SELECT * FROM users WHERE id = 1'));
console.log(mysqlContext.saveData({ name: '张三', age: 30 }));
console.log(mysqlContext.disconnect());
// PostgreSQL 使用示例
const postgresqlContext = createDatabaseContext('postgresql');
console.log(postgresqlContext.connect());
console.log(postgresqlContext.executeSQL('SELECT * FROM users'));
console.log(postgresqlContext.fetchData('SELECT * FROM users WHERE id = 1'));
console.log(postgresqlContext.saveData({ name: '李四', age: 25 }));
console.log(postgresqlContext.disconnect());3. 游戏角色装备系统
在游戏开发中,抽象工厂模式可以用于创建不同主题的角色装备:
javascript
// 装备接口
class Weapon {
getType() {
throw new Error('必须实现 getType 方法');
}
attack() {
throw new Error('必须实现 attack 方法');
}
}
class Armor {
getType() {
throw new Error('必须实现 getType 方法');
}
defend() {
throw new Error('必须实现 defend 方法');
}
}
class Mount {
getType() {
throw new Error('必须实现 getType 方法');
}
move() {
throw new Error('必须实现 move 方法');
}
}
// 中世纪主题装备
class MedievalSword extends Weapon {
getType() {
return '中世纪剑';
}
attack() {
return '挥舞中世纪剑进行攻击';
}
}
class MedievalArmor extends Armor {
getType() {
return '中世纪盔甲';
}
defend() {
return '穿上中世纪盔甲进行防御';
}
}
class MedievalHorse extends Mount {
getType() {
return '中世纪战马';
}
move() {
return '骑着中世纪战马冲锋';
}
}
// 未来主题装备
class LaserGun extends Weapon {
getType() {
return '激光枪';
}
attack() {
return '使用激光枪进行攻击';
}
}
class EnergyShield extends Armor {
getType() {
return '能量护盾';
}
defend() {
return '激活能量护盾进行防御';
}
}
class Hovercraft extends Mount {
getType() {
return '悬浮车';
}
move() {
return '驾驶悬浮车快速移动';
}
}
// 装备工厂接口
class EquipmentFactory {
createWeapon() {
throw new Error('必须实现 createWeapon 方法');
}
createArmor() {
throw new Error('必须实现 createArmor 方法');
}
createMount() {
throw new Error('必须实现 createMount 方法');
}
}
// 中世纪装备工厂
class MedievalEquipmentFactory extends EquipmentFactory {
createWeapon() {
return new MedievalSword();
}
createArmor() {
return new MedievalArmor();
}
createMount() {
return new MedievalHorse();
}
}
// 未来装备工厂
class FutureEquipmentFactory extends EquipmentFactory {
createWeapon() {
return new LaserGun();
}
createArmor() {
return new EnergyShield();
}
createMount() {
return new Hovercraft();
}
}
// 角色类
class Character {
constructor(factory, name) {
this.factory = factory;
this.name = name;
this.weapon = null;
this.armor = null;
this.mount = null;
}
equip() {
this.weapon = this.factory.createWeapon();
this.armor = this.factory.createArmor();
this.mount = this.factory.createMount();
}
getEquipmentInfo() {
if (!this.weapon || !this.armor || !this.mount) {
throw new Error('角色未装备');
}
return {
name: this.name,
weapon: this.weapon.getType(),
armor: this.armor.getType(),
mount: this.mount.getType()
};
}
attack() {
if (!this.weapon) {
throw new Error('角色未装备武器');
}
return `${this.name} ${this.weapon.attack()}`;
}
defend() {
if (!this.armor) {
throw new Error('角色未装备盔甲');
}
return `${this.name} ${this.armor.defend()}`;
}
move() {
if (!this.mount) {
throw new Error('角色未装备坐骑');
}
return `${this.name} ${this.mount.move()}`;
}
}
// 使用示例
function createCharacter(theme, name) {
let factory;
switch (theme) {
case 'medieval':
factory = new MedievalEquipmentFactory();
break;
case 'future':
factory = new FutureEquipmentFactory();
break;
default:
throw new Error(`不支持的主题: ${theme}`);
}
const character = new Character(factory, name);
character.equip();
return character;
}
// 中世纪角色
const knight = createCharacter('medieval', '骑士');
console.log('骑士装备:', knight.getEquipmentInfo());
console.log(knight.attack());
console.log(knight.defend());
console.log(knight.move());
// 未来角色
const soldier = createCharacter('future', '士兵');
console.log('士兵装备:', soldier.getEquipmentInfo());
console.log(soldier.attack());
console.log(soldier.defend());
console.log(soldier.move());抽象工厂模式与工厂方法模式的对比
工厂方法模式
javascript
// 工厂方法模式关注单一产品
class Creator {
factoryMethod() {
// 创建单一产品
}
}抽象工厂模式
javascript
// 抽象工厂模式关注产品族
class AbstractFactory {
createProductA() {
// 创建产品 A
}
createProductB() {
// 创建产品 B
}
createProductC() {
// 创建产品 C
}
}对比总结
| 特性 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|
| 关注点 | 单一产品 | 产品族 |
| 扩展性 | 添加新产品需要新工厂 | 添加新产品族需要新工厂 |
| 复杂度 | 较低 | 较高 |
| 适用场景 | 单一产品创建 | 一组相关产品创建 |
抽象工厂模式的优缺点
优点
- 产品族一致性:确保创建的产品族具有一致性
- 符合开闭原则:添加新的产品族时无需修改现有代码
- 良好的封装性:客户端不需要知道具体产品的创建细节
- 易于替换产品族:可以轻松切换整个产品族
缺点
- 类数量增加:每增加一个产品族,就需要增加多个类
- 系统复杂度增加:引入了更多的抽象和继承关系
- 难以支持新产品等级:添加新产品等级需要修改工厂接口
总结
抽象工厂模式是创建型设计模式中的重要模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式关注的是产品族的概念,确保创建的产品具有一致性。
通过本章的学习,我们了解了:
- 抽象工厂模式的基本概念和核心思想
- 抽象工厂模式的实现方式
- 抽象工厂模式在实际开发中的应用场景(跨平台UI组件、数据库访问组件族、游戏角色装备系统)
- 抽象工厂模式与工厂方法模式的对比
- 抽象工厂模式的优缺点
抽象工厂模式在现代软件开发中应用广泛,特别是在需要创建一组相关产品对象的场景中,它可以很好地支持系统的扩展性和维护性。
在下一章中,我们将继续探讨其他创建型模式,如建造者模式。