Factory Pattern
JavaScript 工厂模式的实现与应用
问题
实现工厂模式,包括简单工厂、工厂方法和抽象工厂三种形式。
解答
简单工厂
// 产品类
class Car {
constructor(name) {
this.name = name;
}
drive() {
console.log(`${this.name} is driving`);
}
}
class Bike {
constructor(name) {
this.name = name;
}
ride() {
console.log(`${this.name} is riding`);
}
}
// 简单工厂:根据类型创建不同产品
class VehicleFactory {
static create(type, name) {
switch (type) {
case 'car':
return new Car(name);
case 'bike':
return new Bike(name);
default:
throw new Error(`Unknown vehicle type: ${type}`);
}
}
}
// 使用
const car = VehicleFactory.create('car', 'Tesla');
const bike = VehicleFactory.create('bike', 'Giant');
car.drive(); // Tesla is driving
bike.ride(); // Giant is riding
工厂方法
// 抽象工厂类
class VehicleFactory {
// 工厂方法,由子类实现
createVehicle() {
throw new Error('Must implement createVehicle');
}
// 业务逻辑
deliver() {
const vehicle = this.createVehicle();
vehicle.prepare();
vehicle.ship();
return vehicle;
}
}
// 具体产品
class Car {
prepare() {
console.log('Preparing car...');
}
ship() {
console.log('Shipping car by truck');
}
}
class Ship {
prepare() {
console.log('Preparing ship...');
}
ship() {
console.log('Ship sails away');
}
}
// 具体工厂
class CarFactory extends VehicleFactory {
createVehicle() {
return new Car();
}
}
class ShipFactory extends VehicleFactory {
createVehicle() {
return new Ship();
}
}
// 使用:客户端只依赖抽象工厂
function orderVehicle(factory) {
return factory.deliver();
}
orderVehicle(new CarFactory());
orderVehicle(new ShipFactory());
抽象工厂
// 抽象产品
class Button {
render() {}
}
class Input {
render() {}
}
// Windows 风格产品
class WindowsButton extends Button {
render() {
return '<button class="win-btn">Windows Button</button>';
}
}
class WindowsInput extends Input {
render() {
return '<input class="win-input" />';
}
}
// Mac 风格产品
class MacButton extends Button {
render() {
return '<button class="mac-btn">Mac Button</button>';
}
}
class MacInput extends Input {
render() {
return '<input class="mac-input" />';
}
}
// 抽象工厂:创建一系列相关产品
class UIFactory {
createButton() {}
createInput() {}
}
// 具体工厂
class WindowsUIFactory extends UIFactory {
createButton() {
return new WindowsButton();
}
createInput() {
return new WindowsInput();
}
}
class MacUIFactory extends UIFactory {
createButton() {
return new MacButton();
}
createInput() {
return new MacInput();
}
}
// 使用:根据平台选择工厂
function createUI(factory) {
const button = factory.createButton();
const input = factory.createInput();
return {
button: button.render(),
input: input.render()
};
}
const platform = navigator.platform.includes('Mac') ? 'mac' : 'windows';
const factory = platform === 'mac' ? new MacUIFactory() : new WindowsUIFactory();
console.log(createUI(factory));
实际应用:React 组件工厂
// 根据配置动态创建表单组件
const componentMap = {
text: ({ name, label }) => (
<input type="text" name={name} placeholder={label} />
),
select: ({ name, label, options }) => (
<select name={name}>
{options.map(opt => <option key={opt.value} value={opt.value}>{opt.label}</option>)}
</select>
),
checkbox: ({ name, label }) => (
<label><input type="checkbox" name={name} /> {label}</label>
)
};
// 组件工厂
function createFormField(config) {
const Component = componentMap[config.type];
if (!Component) {
throw new Error(`Unknown field type: ${config.type}`);
}
return <Component key={config.name} {...config} />;
}
// 使用
const formConfig = [
{ type: 'text', name: 'username', label: 'Username' },
{ type: 'select', name: 'role', label: 'Role', options: [
{ value: 'admin', label: 'Admin' },
{ value: 'user', label: 'User' }
]},
{ type: 'checkbox', name: 'agree', label: 'I agree' }
];
function DynamicForm({ config }) {
return <form>{config.map(createFormField)}</form>;
}
关键点
- 简单工厂:一个工厂类,通过参数决定创建哪种产品,适合产品种类少的场景
- 工厂方法:定义创建对象的接口,让子类决定实例化哪个类,符合开闭原则
- 抽象工厂:创建一系列相关产品,保证产品族的一致性
- 使用场景:对象创建逻辑复杂、需要解耦创建和使用、需要统一管理对象创建
- 前端应用:动态组件渲染、主题切换、跨平台适配
目录