在软件工程中,设计模式是解决常见问题的高效模板,而工厂模式(Factory Pattern)作为创建型模式之一,因其在对象创建方面的灵活性和可扩展性,广泛应用于各种编程语言,包括 JavaScript。JavaScript 作为一门动态、灵活的语言,其函数式和面向对象特性为工厂模式的实现提供了独特的舞台。
1. 工厂模式的基础
1.1 什么是工厂模式?
工厂模式是一种创建型设计模式,旨在通过一个工厂对象或函数来创建其他对象,而无需直接使用 new
关键字或显式调用构造函数。它的核心思想是将对象的创建逻辑封装起来,解耦客户端代码与具体类的实现。
工厂模式的主要目标:
- 抽象创建过程:隐藏对象创建的复杂逻辑。
- 提高可扩展性:支持动态添加新类型的对象。
- 降低耦合:客户端只需与工厂交互,无需了解具体类。
在 JavaScript 中,工厂模式可以通过函数、类或对象字面量实现,灵活性极高。
1.2 工厂模式的类型
工厂模式通常分为以下几种:
- 简单工厂(Simple Factory):通过一个工厂函数根据参数创建不同类型的对象。
- 工厂方法(Factory Method):定义一个创建对象的接口,由子类实现具体创建逻辑。
- 抽象工厂(Abstract Factory):创建一系列相关或依赖对象的工厂,适合复杂对象族。
本文将逐一探讨这些类型在 JavaScript 中的实现。
1.3 为什么在 JavaScript 中使用工厂模式?
JavaScript 的动态类型和原型继承特性使得工厂模式特别适合:
- 动态类型:无需显式声明对象类型,工厂可以根据条件创建不同对象。
- 函数式编程:工厂函数天然契合 JavaScript 的函数式风格。
- 模块化开发:工厂模式便于在模块化代码中封装创建逻辑。
- 前端场景:如组件渲染、数据模型实例化等场景需要动态创建对象。
2. 简单工厂模式
简单工厂模式是最基础的工厂模式,通过一个工厂函数根据输入参数返回不同类型的对象。
2.1 基本实现
假设我们要创建一个用户管理系统,支持不同类型的用户(如管理员、普通用户)。
javascript
function UserFactory() {
function Admin(name) {
this.name = name;
this.role = 'admin';
this.permissions = ['read', 'write', 'delete'];
}
function Member(name) {
this.name = name;
this.role = 'member';
this.permissions = ['read'];
}
return {
createUser(type, name) {
switch (type) {
case 'admin':
return new Admin(name);
case 'member':
return new Member(name);
default:
throw new Error('Invalid user type');
}
},
};
}
const userFactory = UserFactory();
const admin = userFactory.createUser('admin', 'Alice');
const member = userFactory.createUser('member', 'Bob');
console.log(admin); // { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // { name: 'Bob', role: 'member', permissions: ['read'] }
2.2 使用 ES6 类
使用类改写上述例子,增强可读性和类型安全:
javascript
class User {
constructor(name, role, permissions) {
this.name = name;
this.role = role;
this.permissions = permissions;
}
}
class Admin extends User {
constructor(name) {
super(name, 'admin', ['read', 'write', 'delete']);
}
}
class Member extends User {
constructor(name) {
super(name, 'member', ['read']);
}
}
class UserFactory {
static createUser(type, name) {
switch (type) {
case 'admin':
return new Admin(name);
case 'member':
return new Member(name);
default:
throw new Error('Invalid user type');
}
}
}
const admin = UserFactory.createUser('admin', 'Alice');
const member = UserFactory.createUser('member', 'Bob');
console.log(admin); // Admin { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // Member { name: 'Bob', role: 'member', permissions: ['read'] }
2.3 动态注册类型
为提高扩展性,可以允许动态注册新用户类型:
javascript
class UserFactory {
constructor() {
this.types = new Map();
}
registerType(type, constructor) {
this.types.set(type, constructor);
}
createUser(type, name) {
const Constructor = this.types.get(type);
if (!Constructor) {
throw new Error(`Invalid user type: ${type}`);
}
return new Constructor(name);
}
}
class Admin {
constructor(name) {
this.name = name;
this.role = 'admin';
this.permissions = ['read', 'write', 'delete'];
}
}
class Member {
constructor(name) {
this.name = name;
this.role = 'member';
this.permissions = ['read'];
}
}
const userFactory = new UserFactory();
userFactory.registerType('admin', Admin);
userFactory.registerType('member', Member);
const admin = userFactory.createUser('admin', 'Alice');
const member = userFactory.createUser('member', 'Bob');
console.log(admin); // Admin { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // Member { name: 'Bob', role: 'member', permissions: ['read'] }
2.4 应用场景
简单工厂模式适用于:
- 对象类型有限:如用户角色、UI 组件类型。
- 创建逻辑简单:无需复杂的初始化过程。
- 集中管理:希望将对象创建逻辑统一封装。
3. 工厂方法模式
工厂方法模式通过定义一个抽象工厂接口,由子类实现具体创建逻辑,适合需要更高灵活性和扩展性的场景。
3.1 基本实现
假设我们要为不同类型的文档(PDF、Word)创建编辑器。
javascript
class DocumentEditor {
createDocument() {
throw new Error('Method must be implemented');
}
}
class PdfEditor extends DocumentEditor {
createDocument() {
return {
type: 'PDF',
open: () => console.log('Opening PDF document'),
save: () => console.log('Saving PDF document'),
};
}
}
class WordEditor extends DocumentEditor {
createDocument() {
return {
type: 'Word',
open: () => console.log('Opening Word document'),
save: () => console.log('Saving Word document'),
};
}
}
function createEditor(type) {
switch (type) {
case 'pdf':
return new PdfEditor();
case 'word':
return new WordEditor();
default:
throw new Error('Invalid editor type');
}
}
const pdfEditor = createEditor('pdf');
const wordEditor = createEditor('word');
const pdfDoc = pdfEditor.createDocument();
const wordDoc = wordEditor.createDocument();
pdfDoc.open(); // Opening PDF document
wordDoc.save(); // Saving Word document
3.2 使用工厂类
将工厂逻辑封装为类:
javascript
class Document {
open() {
throw new Error('Method must be implemented');
}
save() {
throw new Error('Method must be implemented');
}
}
class PdfDocument extends Document {
open() {
console.log('Opening PDF document');
}
save() {
console.log('Saving PDF document');
}
}
class WordDocument extends Document {
open() {
console.log('Opening Word document');
}
save() {
console.log('Saving Word document');
}
}
class DocumentFactory {
createDocument() {
throw new Error('Method must be implemented');
}
}
class PdfFactory extends DocumentFactory {
createDocument() {
return new PdfDocument();
}
}
class WordFactory extends DocumentFactory {
createDocument() {
return new WordDocument();
}
}
const pdfFactory = new PdfFactory();
const wordFactory = new WordFactory();
const pdfDoc = pdfFactory.createDocument();
const wordDoc = wordFactory.createDocument();
pdfDoc.open(); // Opening PDF document
wordDoc.save(); // Saving Word document
3.3 动态工厂
支持动态添加工厂类型:
javascript
class DocumentFactory {
constructor() {
this.factories = new Map();
}
registerFactory(type, factory) {
this.factories.set(type, factory);
}
createDocument(type) {
const factory = this.factories.get(type);
if (!factory) {
throw new Error(`Invalid document type: ${type}`);
}
return factory.createDocument();
}
}
const documentFactory = new DocumentFactory();
documentFactory.registerFactory('pdf', new PdfFactory());
documentFactory.registerFactory('word', new WordFactory());
const pdfDoc = documentFactory.createDocument('pdf');
const wordDoc = documentFactory.createDocument('word');
pdfDoc.open(); // Opening PDF document
wordDoc.save(); // Saving Word document
3.4 应用场景
工厂方法模式适用于:
- 需要子类扩展:如不同类型的编辑器、渲染器。
- 创建逻辑复杂:涉及多步骤初始化。
- 动态类型选择:运行时决定创建哪种对象。
4. 抽象工厂模式
抽象工厂模式用于创建一系列相关或依赖对象的工厂,适合复杂对象族的场景。
4.1 基本实现
假设我们要为不同平台(Web、Mobile)创建 UI 组件(如按钮、下拉框)。
javascript
class Button {
render() {
throw new Error('Method must be implemented');
}
}
class Dropdown {
render() {
throw new Error('Method must be implemented');
}
}
class WebButton extends Button {
render() {
console.log('Rendering Web button');
}
}
class WebDropdown extends Dropdown {
render() {
console.log('Rendering Web dropdown');
}
}
class MobileButton extends Button {
render() {
console.log('Rendering Mobile button');
}
}
class MobileDropdown extends Dropdown {
render() {
console.log('Rendering Mobile dropdown');
}
}
class UIFactory {
createButton() {
throw new Error('Method must be implemented');
}
createDropdown() {
throw new Error('Method must be implemented');
}
}
class WebUIFactory extends UIFactory {
createButton() {
return new WebButton();
}
createDropdown() {
return new WebDropdown();
}
}
class MobileUIFactory extends UIFactory {
createButton() {
return new MobileButton();
}
createDropdown() {
return new MobileDropdown();
}
}
function createUIFactory(platform) {
switch (platform) {
case 'web':
return new WebUIFactory();
case 'mobile':
return new MobileUIFactory();
default:
throw new Error('Invalid platform');
}
}
const webFactory = createUIFactory('web');
const mobileFactory = createUIFactory('mobile');
const webButton = webFactory.createButton();
const webDropdown = webFactory.createDropdown();
const mobileButton = mobileFactory.createButton();
const mobileDropdown = mobileFactory.createDropdown();
webButton.render(); // Rendering Web button
mobileDropdown.render(); // Rendering Mobile dropdown
4.2 使用对象字面量
在 JavaScript 中,可以用对象字面量简化抽象工厂:
javascript
const WebUIFactory = {
createButton() {
return {
render: () => console.log('Rendering Web button'),
};
},
createDropdown() {
return {
render: () => console.log('Rendering Web dropdown'),
};
},
};
const MobileUIFactory = {
createButton() {
return {
render: () => console.log('Rendering Mobile button'),
};
},
createDropdown() {
return {
render: () => console.log('Rendering Mobile dropdown'),
};
},
};
const factories = {
web: WebUIFactory,
mobile: MobileUIFactory,
};
function createUIFactory(platform) {
const factory = factories[platform];
if (!factory) {
throw new Error(`Invalid platform: ${platform}`);
}
return factory;
}
const webFactory = createUIFactory('web');
const mobileFactory = createUIFactory('mobile');
webFactory.createButton().render(); // Rendering Web button
mobileFactory.createDropdown().render(); // Rendering Mobile dropdown
4.3 应用场景
抽象工厂模式适用于:
- 相关对象族:如 UI 组件、数据库连接驱动。
- 跨平台开发:Web、移动或桌面应用的组件创建。
- 复杂初始化:需要创建一组相互依赖的对象。
5. 工厂模式与 TypeScript
TypeScript 的静态类型系统为工厂模式提供了更强的类型安全。
5.1 简单工厂
typescript
interface User {
name: string;
role: string;
permissions: string[];
}
class Admin implements User {
name: string;
role = 'admin';
permissions = ['read', 'write', 'delete'];
constructor(name: string) {
this.name = name;
}
}
class Member implements User {
name: string;
role = 'member';
permissions = ['read'];
constructor(name: string) {
this.name = name;
}
}
class UserFactory {
static createUser(type: 'admin' | 'member', name: string): User {
switch (type) {
case 'admin':
return new Admin(name);
case 'member':
return new Member(name);
default:
throw new Error('Invalid user type');
}
}
}
const admin = UserFactory.createUser('admin', 'Alice');
const member = UserFactory.createUser('member', 'Bob');
console.log(admin); // Admin { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // Member { name: 'Bob', role: 'member', permissions: ['read'] }
5.2 工厂方法
typescript
interface Document {
open(): void;
save(): void;
}
class PdfDocument implements Document {
open() {
console.log('Opening PDF document');
}
save() {
console.log('Saving PDF document');
}
}
class WordDocument implements Document {
open() {
console.log('Opening Word document');
}
save() {
console.log('Saving Word document');
}
}
interface DocumentFactory {
createDocument(): Document;
}
class PdfFactory implements DocumentFactory {
createDocument(): Document {
return new PdfDocument();
}
}
class WordFactory implements DocumentFactory {
createDocument(): Document {
return new WordDocument();
}
}
const pdfFactory: DocumentFactory = new PdfFactory();
const wordFactory: DocumentFactory = new WordFactory();
const pdfDoc = pdfFactory.createDocument();
const wordDoc = wordFactory.createDocument();
pdfDoc.open(); // Opening PDF document
wordDoc.save(); // Saving Word document
5.3 抽象工厂
typescript
interface Button {
render(): void;
}
interface Dropdown {
render(): void;
}
interface UIFactory {
createButton(): Button;
createDropdown(): Dropdown;
}
class WebButton implements Button {
render() {
console.log('Rendering Web button');
}
}
class WebDropdown implements Dropdown {
render() {
console.log('Rendering Web dropdown');
}
}
class MobileButton implements Button {
render() {
console.log('Rendering Mobile button');
}
}
class MobileDropdown implements Dropdown {
render() {
console.log('Rendering Mobile dropdown');
}
}
class WebUIFactory implements UIFactory {
createButton(): Button {
return new WebButton();
}
createDropdown(): Dropdown {
return new WebDropdown();
}
}
class MobileUIFactory implements UIFactory {
createButton(): Button {
return new MobileButton();
}
createDropdown(): Dropdown {
return new MobileDropdown();
}
}
const webFactory: UIFactory = new WebUIFactory();
const mobileFactory: UIFactory = new MobileUIFactory();
webFactory.createButton().render(); // Rendering Web button
mobileFactory.createDropdown().render(); // Rendering Mobile dropdown
5.4 类型安全的动态工厂
typescript
interface User {
name: string;
role: string;
permissions: string[];
}
type UserConstructor = new (name: string) => User;
class UserFactory {
private types: Map<string, UserConstructor> = new Map();
registerType(type: string, constructor: UserConstructor) {
this.types.set(type, constructor);
}
createUser(type: string, name: string): User {
const Constructor = this.types.get(type);
if (!Constructor) {
throw new Error(`Invalid user type: ${type}`);
}
return new Constructor(name);
}
}
const userFactory = new UserFactory();
userFactory.registerType('admin', Admin);
userFactory.registerType('member', Member);
const admin = userFactory.createUser('admin', 'Alice');
const member = userFactory.createUser('member', 'Bob');
6. 工厂模式在前端框架中的应用
6.1 React 组件工厂
在 React 中,工厂模式常用于动态创建组件。
javascript
const Button = ({ label }) => <button>{label}</button>;
const Input = ({ placeholder }) => <input placeholder={placeholder} />;
const Card = ({ title }) => <div>{title}</div>;
const ComponentFactory = {
button: Button,
input: Input,
card: Card,
};
function createComponent(type, props) {
const Component = ComponentFactory[type];
if (!Component) {
throw new Error(`Invalid component type: ${type}`);
}
return <Component {...props} />;
}
// 使用
const App = () => (
<div>
{createComponent('button', { label: 'Click Me' })}
{createComponent('input', { placeholder: 'Enter text' })}
{createComponent('card', { title: 'Hello' })}
</div>
);
6.2 Vue 组件工厂
在 Vue 中,动态组件可以通过工厂模式实现:
javascript
import { defineComponent } from 'vue';
const Button = defineComponent({
props: ['label'],
template: `<button>{{ label }}</button>`,
});
const Input = defineComponent({
props: ['placeholder'],
template: `<input :placeholder="placeholder" />`,
});
const ComponentFactory = {
button: Button,
input: Input,
};
function createComponent(type, props) {
const Component = ComponentFactory[type];
if (!Component) {
throw new Error(`Invalid component type: ${type}`);
}
return { component: Component, props };
}
// 使用
export default defineComponent({
setup() {
const components = [
createComponent('button', { label: 'Click Me' }),
createComponent('input', { placeholder: 'Enter text' }),
];
return { components };
},
template: `
<div>
<component
v-for="(item, index) in components"
:key="index"
:is="item.component"
v-bind="item.props"
/>
</div>
`,
});
6.3 React + TypeScript
在 React 中结合 TypeScript:
typescript
interface ComponentProps {
[key: string]: any;
}
interface ComponentFactory {
[key: string]: React.ComponentType<ComponentProps>;
}
const Button: React.FC<{ label: string }> = ({ label }) => <button>{label}</button>;
const Input: React.FC<{ placeholder: string }> = ({ placeholder }) => <input placeholder={placeholder} />;
const ComponentFactory: ComponentFactory = {
button: Button,
input: Input,
};
function createComponent(type: string, props: ComponentProps): JSX.Element {
const Component = ComponentFactory[type];
if (!Component) {
throw new Error(`Invalid component type: ${type}`);
}
return <Component {...props} />;
}
const App: React.FC = () => (
<div>
{createComponent('button', { label: 'Click Me' })}
{createComponent('input', { placeholder: 'Enter text' })}
</div>
);
7. 工厂模式与函数式编程
JavaScript 的函数式编程特性为工厂模式提供了新的实现方式。
7.1 高阶函数工厂
使用高阶函数创建工厂:
javascript
const createUserFactory = (role, permissions) => (name) => ({
name,
role,
permissions,
});
const createAdmin = createUserFactory('admin', ['read', 'write', 'delete']);
const createMember = createUserFactory('member', ['read']);
const admin = createAdmin('Alice');
const member = createMember('Bob');
console.log(admin); // { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // { name: 'Bob', role: 'member', permissions: ['read'] }
7.2 柯里化工厂
使用柯里化增强灵活性:
javascript
const userFactory = (role) => (permissions) => (name) => ({
name,
role,
permissions,
});
const adminFactory = userFactory('admin')(['read', 'write', 'delete']);
const memberFactory = userFactory('member')(['read']);
const admin = adminFactory('Alice');
const member = memberFactory('Bob');
console.log(admin); // { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // { name: 'Bob', role: 'member', permissions: ['read'] }
7.3 结合 TypeScript
typescript
interface User {
name: string;
role: string;
permissions: string[];
}
type UserFactory = (name: string) => User;
const createUserFactory = (role: string, permissions: string[]): UserFactory => (
name: string
): User => ({
name,
role,
permissions,
});
const createAdmin = createUserFactory('admin', ['read', 'write', 'delete']);
const createMember = createUserFactory('member', ['read']);
const admin = createAdmin('Alice');
const member = createMember('Bob');
8. 性能优化
8.1 缓存工厂实例
为避免重复创建工厂,使用缓存:
javascript
const factoryCache = new Map();
function getUserFactory(type) {
if (factoryCache.has(type)) {
return factoryCache.get(type);
}
const factory = {
admin: () => (name) => ({
name,
role: 'admin',
permissions: ['read', 'write', 'delete'],
}),
member: () => (name) => ({
name,
role: 'member',
permissions: ['read'],
}),
}[type];
if (!factory) {
throw new Error(`Invalid type: ${type}`);
}
factoryCache.set(type, factory);
return factory;
}
const adminFactory = getUserFactory('admin');
const memberFactory = getUserFactory('member');
const admin = adminFactory('Alice');
const member = memberFactory('Bob');
8.2 单例工厂
确保工厂返回单例实例:
javascript
class UserFactory {
private static instance: UserFactory;
private constructor() {}
static getInstance(): UserFactory {
if (!UserFactory.instance) {
UserFactory.instance = new UserFactory();
}
return UserFactory.instance;
}
createUser(type, name) {
switch (type) {
case 'admin':
return { name, role: 'admin', permissions: ['read', 'write', 'delete'] };
case 'member':
return { name, role: 'member', permissions: ['read'] };
default:
throw new Error('Invalid user type');
}
}
}
const factory = UserFactory.getInstance();
const admin = factory.createUser('admin', 'Alice');
const member = factory.createUser('member', 'Bob');
8.3 避免过度创建
通过对象池复用对象:
javascript
class UserPool {
private pool: Map<string, any> = new Map();
getUser(type, name) {
const key = `${type}:${name}`;
if (this.pool.has(key)) {
return this.pool.get(key);
}
const user = {
admin: { name, role: 'admin', permissions: ['read', 'write', 'delete'] },
member: { name, role: 'member', permissions: ['read'] },
}[type];
if (!user) {
throw new Error(`Invalid type: ${type}`);
}
this.pool.set(key, user);
return user;
}
}
const userPool = new UserPool();
const admin = userPool.getUser('admin', 'Alice');
const cachedAdmin = userPool.getUser('admin', 'Alice');
console.log(admin === cachedAdmin); // true
9. 工厂模式与现代 JavaScript 特性
9.1 异步工厂
处理异步创建逻辑:
javascript
async function createUserFactory(type) {
const response = await fetch(`/api/user-types/${type}`);
const { role, permissions } = await response.json();
return (name) => ({
name,
role,
permissions,
});
}
(async () => {
const adminFactory = await createUserFactory('admin');
const memberFactory = await createUserFactory('member');
const admin = adminFactory('Alice');
const member = memberFactory('Bob');
console.log(admin);
console.log(member);
})();
9.2 Proxy 增强工厂
使用 Proxy
动态拦截创建逻辑:
javascript
const userFactory = new Proxy(
{},
{
get(target, type) {
const configs = {
admin: { role: 'admin', permissions: ['read', 'write', 'delete'] },
member: { role: 'member', permissions: ['read'] },
};
const config = configs[type];
if (!config) {
throw new Error(`Invalid type: ${type}`);
}
return (name) => ({
name,
...config,
});
},
}
);
const admin = userFactory.admin('Alice');
const member = userFactory.member('Bob');
console.log(admin); // { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] }
console.log(member); // { name: 'Bob', role: 'member', permissions: ['read'] }
9.3 Symbol 作为类型标识
使用 Symbol
提高类型安全性:
javascript
const ADMIN = Symbol('admin');
const MEMBER = Symbol('member');
const UserFactory = {
createUser(type, name) {
const configs = {
[ADMIN]: { role: 'admin', permissions: ['read', 'write', 'delete'] },
[MEMBER]: { role: 'member', permissions: ['read'] },
};
const config = configs[type];
if (!config) {
throw new Error('Invalid user type');
}
return { name, ...config };
},
};
const admin = UserFactory.createUser(ADMIN, 'Alice');
const member = UserFactory.createUser(MEMBER, 'Bob');
console.log(admin);
console.log(member);
10. 工厂模式在 Node.js 中的应用
10.1 数据库连接工厂
为不同数据库(MySQL、MongoDB)创建连接:
javascript
class DatabaseConnection {
connect() {
throw new Error('Method must be implemented');
}
}
class MySQLConnection extends DatabaseConnection {
connect() {
console.log('Connecting to MySQL');
}
}
class MongoDBConnection extends DatabaseConnection {
connect() {
console.log('Connecting to MongoDB');
}
}
class DatabaseFactory {
static createConnection(type) {
switch (type) {
case 'mysql':
return new MySQLConnection();
case 'mongodb':
return new MongoDBConnection();
default:
throw new Error('Invalid database type');
}
}
}
const mysqlConn = DatabaseFactory.createConnection('mysql');
const mongodbConn = DatabaseFactory.createConnection('mongodb');
mysqlConn.connect(); // Connecting to MySQL
mongodbConn.connect(); // Connecting to MongoDB
10.2 日志工厂
为不同日志级别创建日志器:
javascript
class Logger {
log(message) {
throw new Error('Method must be implemented');
}
}
class InfoLogger extends Logger {
log(message) {
console.log(`[INFO] ${message}`);
}
}
class ErrorLogger extends Logger {
log(message) {
console.error(`[ERROR] ${message}`);
}
}
const LoggerFactory = {
createLogger(level) {
const loggers = {
info: InfoLogger,
error: ErrorLogger,
};
const LoggerClass = loggers[level];
if (!LoggerClass) {
throw new Error(`Invalid log level: ${level}`);
}
return new LoggerClass();
},
};
const infoLogger = LoggerFactory.createLogger('info');
const errorLogger = LoggerFactory.createLogger('error');
infoLogger.log('Operation completed'); // [INFO] Operation completed
errorLogger.log('Something went wrong'); // [ERROR] Something went wrong
11. 测试工厂模式
11.1 使用 Jest 测试简单工厂
javascript
const UserFactory = require('./userFactory');
describe('UserFactory', () => {
it('should create an admin user', () => {
const admin = UserFactory.createUser('admin', 'Alice');
expect(admin.role).toBe('admin');
expect(admin.permissions).toEqual(['read', 'write', 'delete']);
});
it('should create a member user', () => {
const member = UserFactory.createUser('member', 'Bob');
expect(member.role).toBe('member');
expect(member.permissions).toEqual(['read']);
});
it('should throw error for invalid type', () => {
expect(() => UserFactory.createUser('invalid', 'Charlie')).toThrow('Invalid user type');
});
});
11.2 测试 TypeScript 工厂
typescript
import UserFactory from './userFactory';
describe('UserFactory', () => {
it('should create an admin user', () => {
const admin = UserFactory.createUser('admin', 'Alice');
expect(admin.role).toBe('admin');
expect(admin.permissions).toEqual(['read', 'write', 'delete']);
});
it('should create a member user', () => {
const member = UserFactory.createUser('member', 'Bob');
expect(member.role).toBe('member');
expect(member.permissions).toEqual(['read']);
});
it('should throw error for invalid type', () => {
expect(() => UserFactory.createUser('invalid' as any, 'Charlie')).toThrow('Invalid user type');
});
});
12. 工厂模式与模块化
12.1 CommonJS 模块
javascript
// userFactory.js
class Admin {
constructor(name) {
this.name = name;
this.role = 'admin';
this.permissions = ['read', 'write', 'delete'];
}
}
class Member {
constructor(name) {
this.name = name;
this.role = 'member';
this.permissions = ['read'];
}
}
module.exports = {
createUser(type, name) {
switch (type) {
case 'admin':
return new Admin(name);
case 'member':
return new Member(name);
default:
throw new Error('Invalid user type');
}
},
};
// app.js
const UserFactory = require('./userFactory');
const admin = UserFactory.createUser('admin', 'Alice');
console.log(admin);
12.2 ES Modules
javascript
// userFactory.mjs
export class Admin {
constructor(name) {
this.name = name;
this.role = 'admin';
this.permissions = ['read', 'write', 'delete'];
}
}
export class Member {
constructor(name) {
this.name = name;
this.role = 'member';
this.permissions = ['read'];
}
}
export function createUser(type, name) {
switch (type) {
case 'admin':
return new Admin(name);
case 'member':
return new Member(name);
default:
throw new Error('Invalid user type');
}
}
// app.mjs
import { createUser } from './userFactory.mjs';
const admin = createUser('admin', 'Alice');
console.log(admin);
13. 工厂模式与依赖注入
工厂模式常与依赖注入结合,提升代码灵活性。
javascript
class DatabaseService {
query() {
console.log('Executing database query');
}
}
class AuthService {
login() {
console.log('User logged in');
}
}
class ServiceFactory {
static createService(type, dependencies = {}) {
switch (type) {
case 'database':
return new DatabaseService(dependencies);
case 'auth':
return new AuthService(dependencies);
default:
throw new Error('Invalid service type');
}
}
}
const dbService = ServiceFactory.createService('database');
const authService = ServiceFactory.createService('auth', { db: dbService });
dbService.query(); // Executing database query
authService.login(); // User logged in
14. 工厂模式与异步场景
14.1 异步创建
javascript
async function createApiClient(type) {
const response = await fetch(`/api/config/${type}`);
const config = await response.json();
return {
request: () => console.log(`Request with config: ${JSON.stringify(config)}`),
};
}
(async () => {
const userApi = await createApiClient('user');
const orderApi = await createApiClient('order');
userApi.request(); // Request with config: {...}
orderApi.request(); // Request with config: {...}
})();
14.2 异步工厂类
javascript
class ApiClientFactory {
async createClient(type) {
const response = await fetch(`/api/config/${type}`);
const config = await response.json();
return {
request: () => console.log(`Request with config: ${JSON.stringify(config)}`),
};
}
}
const factory = new ApiClientFactory();
(async () => {
const userApi = await factory.createClient('user');
const orderApi = await factory.createClient('order');
userApi.request();
orderApi.request();
})();
15. 工厂模式与错误处理
15.1 集中错误处理
javascript
class UserFactory {
static createUser(type, name) {
try {
switch (type) {
case 'admin':
return { name, role: 'admin', permissions: ['read', 'write', 'delete'] };
case 'member':
return { name, role: 'member', permissions: ['read'] };
default:
throw new Error(`Invalid user type: ${type}`);
}
} catch (error) {
console.error(`Factory error: ${error.message}`);
throw error;
}
}
}
try {
const admin = UserFactory.createUser('admin', 'Alice');
const invalid = UserFactory.createUser('invalid', 'Charlie');
} catch (error) {
console.log(`Caught error: ${error.message}`);
}
15.2 自定义错误
javascript
class FactoryError extends Error {
constructor(message) {
super(message);
this.name = 'FactoryError';
}
}
class UserFactory {
static createUser(type, name) {
switch (type) {
case 'admin':
return { name, role: 'admin', permissions: ['read', 'write', 'delete'] };
case 'member':
return { name, role: 'member', permissions: ['read'] };
default:
throw new FactoryError(`Invalid user type: ${type}`);
}
}
}
try {
const admin = UserFactory.createUser('admin', 'Alice');
const invalid = UserFactory.createUser('invalid', 'Charlie');
} catch (error) {
if (error instanceof FactoryError) {
console.log(`Factory error: ${error.message}`);
}
}
16. 工厂模式与单元测试
16.1 Mock 工厂
javascript
const UserFactory = {
createUser(type, name) {
switch (type) {
case 'admin':
return { name, role: 'admin', permissions: ['read', 'write', 'delete'] };
case 'member':
return { name, role: 'member', permissions: ['read'] };
default:
throw new Error('Invalid user type');
}
},
};
jest.mock('./userFactory', () => ({
createUser: jest.fn(),
}));
describe('UserFactory Mock', () => {
it('should mock admin creation', () => {
const mockUser = { name: 'Alice', role: 'admin', permissions: ['read', 'write', 'delete'] };
require('./userFactory').createUser.mockReturnValue(mockUser);
const admin = UserFactory.createUser('admin', 'Alice');
expect(admin).toEqual(mockUser);
expect(UserFactory.createUser).toHaveBeenCalledWith('admin', 'Alice');
});
});
16.2 测试异步工厂
javascript
const ApiClientFactory = {
async createClient(type) {
const response = await fetch(`/api/config/${type}`);
const config = await response.json();
return { request: () => config };
},
};
jest.mock('./apiClientFactory', () => ({
createClient: jest.fn(),
}));
describe('ApiClientFactory', () => {
it('should mock async client creation', async () => {
const mockClient = { request: () => ({ type: 'user' }) };
require('./apiClientFactory').createClient.mockResolvedValue(mockClient);
const client = await ApiClientFactory.createClient('user');
expect(client).toEqual(mockClient);
expect(ApiClientFactory.createClient).toHaveBeenCalledWith('user');
});
});
17. 工厂模式与性能分析
17.1 内存管理
避免创建过多对象:
javascript
class UserFactory {
static cache = new Map();
static createUser(type, name) {
const key = `${type}:${name}`;
if (this.cache.has(key)) {
return this.cache.get(key);
}
const user = {
admin: { name, role: 'admin', permissions: ['read', 'write', 'delete'] },
member: { name, role: 'member', permissions: ['read'] },
}[type];
if (!user) {
throw new Error(`Invalid type: ${type}`);
}
this.cache.set(key, user);
return user;
}
}
const admin1 = UserFactory.createUser('admin', 'Alice');
const admin2 = UserFactory.createUser('admin', 'Alice');
console.log(admin1 === admin2); // true
17.2 性能测试
使用 performance.now
测量工厂性能:
javascript
const start = performance.now();
for (let i = 0; i < 1000; i++) {
UserFactory.createUser('admin', `User${i}`);
}
const end = performance.now();
console.log(`Factory creation took ${end - start}ms`);
18. 工厂模式与前端状态管理
18.1 Redux Action 工厂
javascript
const createAction = (type) => (payload) => ({
type,
payload,
});
const addUser = createAction('ADD_USER');
const removeUser = createAction('REMOVE_USER');
console.log(addUser({ name: 'Alice' })); // { type: 'ADD_USER', payload: { name: 'Alice' } }
console.log(removeUser({ id: 1 })); // { type: 'REMOVE_USER', payload: { id: 1 } }
18.2 Zustand 状态工厂
javascript
import create from 'zustand';
const createUserStore = (role) => create((set) => ({
users: [],
addUser: (name) =>
set((state) => ({
users: [...state.users, { name, role }],
})),
}));
const adminStore = createUserStore('admin');
const memberStore = createUserStore('member');
adminStore.getState().addUser('Alice');
memberStore.getState().addUser('Bob');
console.log(adminStore.getState().users); // [{ name: 'Alice', role: 'admin' }]
console.log(memberStore.getState().users); // [{ name: 'Bob', role: 'member' }]
19. 工厂模式与构建工具
19.1 Webpack Plugin 工厂
javascript
class PluginFactory {
static createPlugin(type) {
const plugins = {
minify: () => ({
apply: (compiler) => {
console.log('Applying minify plugin');
},
}),
bundle: () => ({
apply: (compiler) => {
console.log('Applying bundle plugin');
},
}),
};
const plugin = plugins[type];
if (!plugin) {
throw new Error(`Invalid plugin type: ${type}`);
}
return plugin();
}
}
module.exports = {
plugins: [
PluginFactory.createPlugin('minify'),
PluginFactory.createPlugin('bundle'),
],
};
19.2 Vite Plugin 工厂
javascript
const PluginFactory = {
createPlugin(type) {
const plugins = {
transform: () => ({
name: 'transform-plugin',
transform(code) {
return code.replace('console.log', 'console.debug');
},
}),
optimize: () => ({
name: 'optimize-plugin',
optimize() {
console.log('Optimizing assets');
},
}),
};
const plugin = plugins[type];
if (!plugin) {
throw new Error(`Invalid plugin type: ${type}`);
}
return plugin();
},
};
export default {
plugins: [
PluginFactory.createPlugin('transform'),
PluginFactory.createPlugin('optimize'),
],
};
20. 工厂模式与微前端
20.1 模块工厂
javascript
const ModuleFactory = {
createModule(type) {
const modules = {
header: () => ({
render: () => console.log('Rendering header module'),
}),
content: () => ({
render: () => console.log('Rendering content module'),
}),
};
const module = modules[type];
if (!module) {
throw new Error(`Invalid module type: ${type}`);
}
return module();
},
};
const headerModule = ModuleFactory.createModule('header');
const contentModule = ModuleFactory.createModule('content');
headerModule.render(); // Rendering header module
contentModule.render(); // Rendering content module
20.2 Qiankun 微前端工厂
javascript
import { registerMicroApps, start } from 'qiankun';
const MicroAppFactory = {
createApp(type, config) {
const apps = {
react: {
name: 'reactApp',
entry: '//localhost:3001',
container: '#reactContainer',
activeRule: '/react',
},
vue: {
name: 'vueApp',
entry: '//localhost:3002',
container: '#vueContainer',
activeRule: '/vue',
},
};
const app = apps[type];
if (!app) {
throw new Error(`Invalid app type: ${type}`);
}
return { ...app, ...config };
},
};
const reactApp = MicroAppFactory.createApp('react', {});
const vueApp = MicroAppFactory.createApp('vue', {});
registerMicroApps([reactApp, vueApp]);
start();
21. 工厂模式与 Node.js 中间件
javascript
const MiddlewareFactory = {
createMiddleware(type) {
const middlewares = {
logger: () => (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
},
auth: () => (req, res, next) => {
if (req.headers.authorization) {
next();
} else {
res.status(401).send('Unauthorized');
}
},
};
const middleware = middlewares[type];
if (!middleware) {
throw new Error(`Invalid middleware type: ${type}`);
}
return middleware();
},
};
const express = require('express');
const app = express();
app.use(MiddlewareFactory.createMiddleware('logger'));
app.use(MiddlewareFactory.createMiddleware('auth'));
app.get('/', (req, res) => res.send('Hello World'));
app.listen(3000);
22. 工厂模式与事件处理
javascript
const EventHandlerFactory = {
createHandler(type) {
const handlers = {
click: () => (event) => console.log(`Click at ${event.clientX}, ${event.clientY}`),
keypress: () => (event) => console.log(`Key pressed: ${event.key}`),
};
const handler = handlers[type];
if (!handler) {
throw new Error(`Invalid handler type: ${type}`);
}
return handler();
},
};
document.addEventListener('click', EventHandlerFactory.createHandler('click'));
document.addEventListener('keypress', EventHandlerFactory.createHandler('keypress'));
23. 工厂模式与数据模型
javascript
const ModelFactory = {
createModel(type, data) {
const models = {
user: (data) => ({
id: data.id,
name: data.name,
email: data.email,
getFullName: () => `${data.name} (${data.email})`,
}),
order: (data) => ({
id: data.id,
total: data.total,
createdAt: data.createdAt,
getSummary: () => `Order #${data.id}: $${data.total}`,
}),
};
const model = models[type];
if (!model) {
throw new Error(`Invalid model type: ${type}`);
}
return model(data);
},
};
const user = ModelFactory.createModel('user', {
id: 1,
name: 'Alice',
email: '[email protected]',
});
const order = ModelFactory.createModel('order', {
id: 1,
total: 99.99,
createdAt: '2023-01-01',
});
console.log(user.getFullName()); // Alice ([email protected])
console.log(order.getSummary()); // Order #1: $99.99
24. 工厂模式与插件系统
javascript
const PluginFactory = {
createPlugin(type, options) {
const plugins = {
logger: (options) => ({
log: (message) => console.log(`[${options.level}] ${message}`),
}),
validator: (options) => ({
validate: (data) => data.length >= options.minLength,
}),
};
const plugin = plugins[type];
if (!plugin) {
throw new Error(`Invalid plugin type: ${type}`);
}
return plugin(options);
},
};
const logger = PluginFactory.createPlugin('logger', { level: 'INFO' });
const validator = PluginFactory.createPlugin('validator', { minLength: 5 });
logger.log('System started'); // [INFO] System started
console.log(validator.validate('hello')); // true
console.log(validator.validate('hi')); // false
25. 工厂模式与配置管理
javascript
const ConfigFactory = {
createConfig(type) {
const configs = {
development: () => ({
apiUrl: 'http://localhost:3000',
debug: true,
}),
production: () => ({
apiUrl: 'https://api.example.com',
debug: false,
}),
};
const config = configs[type];
if (!config) {
throw new Error(`Invalid config type: ${type}`);
}
return config();
},
};
const devConfig = ConfigFactory.createConfig('development');
const prodConfig = ConfigFactory.createConfig('production');
console.log(devConfig); // { apiUrl: 'http://localhost:3000', debug: true }
console.log(prodConfig); // { apiUrl: 'https://api.example.com', debug: false }