跳到主要内容前端设计模式深度解析与实战 | 极客日志JavaScript大前端算法
前端设计模式深度解析与实战
综述由AI生成前端设计模式是解决常见问题的可复用方案,涵盖创建型、结构型和行为型三大类。文章通过工厂、单例、观察者等具体案例,结合现代 JavaScript 特性及 React/Vue 实践,展示了如何构建可维护、可扩展的代码架构。重点探讨了中间件、组件化及高阶组件等前端特有模式,并提供了选型指南与最佳实践,帮助开发者避免过度设计,提升工程化水平。
CodeArtist13 浏览 前端设计模式深度解析与实战
一、设计模式概述
在前端开发中,我们常会遇到重复出现的架构问题。设计模式正是针对这些特定上下文的常见问题的可重用解决方案。它们能帮助我们构建更易于维护、扩展和复用的代码。
1.1 设计模式分类
- 创建型模式:专注于对象创建机制,使系统独立于如何创建对象。
- 结构型模式:处理类或对象的组合方式,形成更大的结构。
- 行为型模式:关注对象间的通信、责任分配及算法流程。
二、创建型模式
2.1 工厂模式(Factory Pattern)
将对象创建逻辑封装起来,避免在客户端直接实例化具体类。
class ButtonFactory {
createButton(type) {
switch (type) {
case 'primary':
return new PrimaryButton();
case 'secondary':
return new SecondaryButton();
default:
throw new Error('Unknown button type');
}
}
}
class Dialog {
createButton() {}
render() {
const button = this.createButton();
button.render();
}
}
class WindowsDialog extends Dialog {
createButton() {
return ();
}
}
{
() {
();
}
}
new
WindowsButton
class
WebDialog
extends
Dialog
createButton
return
new
WebButton
2.2 建造者模式(Builder Pattern)
适用于分步骤构建复杂对象,链式调用让配置过程清晰流畅。
class Car {
constructor() {
this.engine = null;
this.seats = 0;
this.gps = false;
}
toString() {
return `Car with ${this.engine} engine, ${this.seats} seats, GPS: ${this.gps}`;
}
}
class CarBuilder {
constructor() {
this.car = new Car();
}
setEngine(engine) {
this.car.engine = engine;
return this;
}
setSeats(seats) {
this.car.seats = seats;
return this;
}
setGPS(hasGPS) {
this.car.gps = hasGPS;
return this;
}
build() {
return this.car;
}
}
const car = new CarBuilder()
.setEngine('V8')
.setSeats(4)
.setGPS(true)
.build();
console.log(car.toString());
2.3 单例模式(Singleton Pattern)
确保一个类只有一个实例,并提供全局访问点。常用于配置管理或日志服务。
class Singleton {
static #instance = null;
constructor() {
if (Singleton.#instance) {
return Singleton.#instance;
}
Singleton.#instance = this;
this.config = {};
}
static getInstance() {
if (!Singleton.#instance) {
Singleton.#instance = new Singleton();
}
return Singleton.#instance;
}
setConfig(key, value) {
this.config[key] = value;
}
getConfig(key) {
return this.config[key];
}
}
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2);
2.4 原型模式(Prototype Pattern)
通过克隆现有对象来创建新对象,适合对象创建成本较高的场景。
class ComponentPrototype {
constructor(name, styles = {}) {
this.name = name;
this.styles = styles;
this.children = [];
}
clone() {
const clone = new ComponentPrototype(this.name);
clone.styles = { ...this.styles };
clone.children = [...this.children];
return clone;
}
addChild(child) {
this.children.push(child);
}
render() {
console.log(`Rendering ${this.name} with styles:`, this.styles);
}
}
const baseButton = new ComponentPrototype('Button', { color: 'blue', padding: '10px' });
const primaryButton = baseButton.clone();
primaryButton.name = 'Primary Button';
primaryButton.styles.color = 'green';
三、结构型模式
3.1 适配器模式(Adapter Pattern)
让不兼容的接口能够协同工作,是解决遗留系统集成的常用手段。
class OldPaymentSystem {
processPayment(amountInDollars) {
console.log(`Processing $${amountInDollars} payment`);
return true;
}
}
class NewPaymentSystem {
processPayment(amountInEuros) {
console.log(`Processing €${amountInEuros} payment`);
return true;
}
}
class PaymentAdapter {
constructor(oldSystem) {
this.oldSystem = oldSystem;
}
processPayment(amountInEuros) {
const amountInDollars = amountInEuros * 1.2;
return this.oldSystem.processPayment(amountInDollars);
}
}
const oldSystem = new OldPaymentSystem();
const adapter = new PaymentAdapter(oldSystem);
adapter.processPayment(100);
3.2 装饰器模式(Decorator Pattern)
class TextComponent {
constructor(text) {
this.text = text;
}
render() {
return this.text;
}
}
class TextDecorator {
constructor(component) {
this.component = component;
}
render() {
return this.component.render();
}
}
class BoldDecorator extends TextDecorator {
render() {
return `<b>${super.render()}</b>`;
}
}
class ItalicDecorator extends TextDecorator {
render() {
return `<i>${super.render()}</i>`;
}
}
class LinkDecorator extends TextDecorator {
constructor(component, url) {
super(component);
this.url = url;
}
render() {
return `<a href="${this.url}">${super.render()}</a>`;
}
}
let text = new TextComponent('Hello World');
text = new BoldDecorator(text);
text = new ItalicDecorator(text);
text = new LinkDecorator(text, 'https://example.com');
console.log(text.render());
3.3 代理模式(Proxy Pattern)
class ImageLoader {
constructor(filename) {
this.filename = filename;
this.loadImage();
}
loadImage() {
console.log(`Loading image: ${this.filename}`);
this.image = `Image data for ${this.filename}`;
}
display() {
console.log(`Displaying: ${this.image}`);
}
}
class ImageProxy {
constructor(filename) {
this.filename = filename;
this.realImage = null;
}
display() {
if (!this.realImage) {
this.realImage = new ImageLoader(this.filename);
}
this.realImage.display();
}
}
const image1 = new ImageProxy('photo1.jpg');
const image2 = new ImageProxy('photo2.jpg');
image1.display();
image1.display();
3.4 外观模式(Facade Pattern)
为子系统中的一组接口提供一个一致的界面,简化复杂系统的调用。
class CPU {
freeze() { console.log('CPU freeze'); }
jump(position) { console.log(`CPU jump to ${position}`); }
execute() { console.log('CPU execute'); }
}
class Memory {
load(position, data) { console.log(`Memory load ${data} at ${position}`); }
}
class HardDrive {
read(lba, size) {
const data = `data from sector ${lba}`;
console.log(`HardDrive read: ${data}`);
return data;
}
}
class ComputerFacade {
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
this.hardDrive = new HardDrive();
}
start() {
console.log('Computer starting...');
this.cpu.freeze();
const bootData = this.hardDrive.read(0, 1024);
this.memory.load(0x0, bootData);
this.cpu.jump(0x0);
this.cpu.execute();
console.log('Computer started!');
}
}
const computer = new ComputerFacade();
computer.start();
3.5 组合模式(Composite Pattern)
以树形结构组合对象,使得用户对单个对象和组合对象的使用具有一致性。
class UIComponent {
constructor(name) {
this.name = name;
this.children = [];
}
add(component) {
this.children.push(component);
}
remove(component) {
const index = this.children.indexOf(component);
if (index > -1) {
this.children.splice(index, 1);
}
}
render() {
console.log(`Rendering ${this.name}`);
this.children.forEach(child => child.render());
}
}
class Button extends UIComponent {
constructor(name) {
super(name);
}
render() {
console.log(`[Button] ${this.name}`);
}
}
class Input extends UIComponent {
constructor(name) {
super(name);
}
render() {
console.log(`[Input] ${this.name}`);
}
}
const form = new UIComponent('Login Form');
form.add(new Input('Username'));
form.add(new Input('Password'));
form.add(new Button('Submit'));
const panel = new UIComponent('Main Panel');
panel.add(form);
panel.render();
四、行为型模式
4.1 观察者模式(Observer Pattern)
定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
const index = this.observers.indexOf(observer);
if (index > -1) {
this.observers.splice(index, 1);
}
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class UserInterface {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received:`, data);
}
}
const newsPublisher = new Subject();
newsPublisher.subscribe(new UserInterface('Mobile App'));
newsPublisher.subscribe(new UserInterface('Web Dashboard'));
newsPublisher.notify('New product launched!');
4.2 发布 - 订阅模式(Pub/Sub Pattern)
class EventBus {
constructor() {
this.events = {};
}
subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
unsubscribe(event, callback) {
if (!this.events[event]) return;
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
publish(event, data) {
if (!this.events[event]) return;
this.events[event].forEach(callback => callback(data));
}
}
const bus = new EventBus();
bus.subscribe('user.login', data => console.log(`[LOG] ${data}`));
bus.publish('user.login', { username: 'john', time: new Date() });
4.3 策略模式(Strategy Pattern)
定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。
class PaymentStrategy {
pay(amount) {}
}
class CreditCardPayment extends PaymentStrategy {
constructor(cardNumber, cvv) {
super();
this.cardNumber = cardNumber;
this.cvv = cvv;
}
pay(amount) {
console.log(`Paid $${amount} with credit card ${this.cardNumber}`);
}
}
class ShoppingCart {
constructor() {
this.items = [];
this.paymentStrategy = null;
}
addItem(item, price) {
this.items.push({ item, price });
}
setPaymentStrategy(strategy) {
this.paymentStrategy = strategy;
}
checkout() {
const total = this.items.reduce((sum, item) => sum + item.price, 0);
console.log(`Total: $${total}`);
if (this.paymentStrategy) {
this.paymentStrategy.pay(total);
this.items = [];
} else {
throw new Error('Payment strategy not set');
}
}
}
const cart = new ShoppingCart();
cart.addItem('Book', 25);
cart.setPaymentStrategy(new CreditCardPayment('1234-5678-9012-3456', '123'));
cart.checkout();
4.4 状态模式(State Pattern)
允许对象内部状态改变时改变其行为,避免大量的条件判断语句。
class OrderState {
constructor(order) {
this.order = order;
}
next() {}
previous() {}
cancel() {}
}
class PendingState extends OrderState {
next() {
this.order.setState(new ProcessingState(this.order));
console.log('Order moved to processing');
}
cancel() {
this.order.setState(new CancelledState(this.order));
console.log('Order cancelled');
}
}
class ProcessingState extends OrderState {
next() {
this.order.setState(new ShippedState(this.order));
console.log('Order shipped');
}
}
class Order {
constructor() {
this.state = new PendingState(this);
}
setState(state) {
this.state = state;
}
next() {
this.state.next();
}
cancel() {
this.state.cancel();
}
}
const order = new Order();
order.next();
order.cancel();
4.5 命令模式(Command Pattern)
将请求封装成对象,支持撤销操作和解耦发送者与接收者。
class Command {
execute() {}
undo() {}
}
class Light {
turnOn() { console.log('Light is ON'); }
turnOff() { console.log('Light is OFF'); }
}
class RemoteControl {
constructor() {
this.commands = [];
this.history = [];
}
setCommand(command) {
this.commands.push(command);
}
pressButton(index) {
if (index < this.commands.length) {
const command = this.commands[index];
command.execute();
this.history.push(command);
}
}
pressUndo() {
if (this.history.length > 0) {
const command = this.history.pop();
command.undo();
}
}
}
const remote = new RemoteControl();
const light = new Light();
remote.setCommand({
execute: () => light.turnOn(),
undo: () => light.turnOff()
});
remote.pressButton(0);
五、前端特定模式
5.1 模块模式(Module Pattern)
利用闭包创建私有作用域,保护内部变量不被外部篡改。
const UserModule = (function () {
let users = [];
let userCount = 0;
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
return {
addUser(name, email) {
const user = {
id: generateId(),
name,
email,
createdAt: new Date()
};
users.push(user);
userCount++;
return user.id;
},
getAllUsers() {
return [...users];
}
};
})();
const userId = UserModule.addUser('John', '[email protected]');
5.2 混入模式(Mixin Pattern)
通过组合扩展类功能,实现代码复用而不必深层次的继承。
const Loggable = Base => class extends Base {
log(message) {
console.log(`[${this.constructor.name}] ${message}`);
}
};
const Serializable = Base => class extends Base {
serialize() {
return JSON.stringify(this);
}
static deserialize(json) {
const data = JSON.parse(json);
return new this(data);
}
};
class Model {
constructor(data = {}) {
Object.assign(this, data);
}
}
class User extends Serializable(Loggable(Model)) {
constructor(data) {
super(data);
}
}
const user = new User({ name: 'John Doe' });
user.log('Created user');
5.3 中间件模式(Middleware Pattern)
处理请求的管道,常用于 Express 等框架中的请求拦截与处理。
class MiddlewarePipeline {
constructor() {
this.middlewares = [];
}
use(middleware) {
this.middlewares.push(middleware);
}
async execute(context, finalHandler) {
let index = -1;
const dispatch = async i => {
if (i <= index) throw new Error('next() called multiple times');
index = i;
let fn = this.middlewares[i];
if (i === this.middlewares.length) fn = finalHandler;
if (!fn) return;
await fn(context, () => dispatch(i + 1));
};
return dispatch(0);
}
}
const pipeline = new MiddlewarePipeline();
pipeline.use(async (ctx, next) => {
console.log('Middleware 1: Logging request');
ctx.startTime = Date.now();
await next();
const duration = Date.now() - ctx.startTime;
console.log(`Middleware 1: Request took ${duration}ms`);
});
5.4 组件模式(Component Pattern)
前端框架的核心思想,将 UI 拆分为独立的、可复用的单元。
class Component {
constructor(props = {}) {
this.props = props;
this.state = {};
this.children = [];
}
setState(newState) {
this.state = { ...this.state, ...newState };
this.render();
}
addChild(child) {
this.children.push(child);
}
mount(container) {
this.container = container;
this.render();
}
render() {
throw new Error('render() must be implemented');
}
}
class Button extends Component {
handleClick = () => {
this.setState({ clicked: true });
if (this.props.onClick) this.props.onClick();
};
render() {
const button = document.createElement('button');
button.textContent = this.props.label || 'Click me';
button.style.backgroundColor = this.state.clicked ? 'green' : 'blue';
button.onclick = this.handleClick;
if (this.container) {
this.container.innerHTML = '';
this.container.appendChild(button);
}
return button;
}
}
六、React/Vue 中的设计模式
6.1 高阶组件(HOC)- React
const withLoading = WrappedComponent => {
return function WithLoadingComponent({ isLoading, ...props }) {
if (isLoading) {
return <div className="loading">Loading...</div>;
}
return <WrappedComponent {...props} />;
};
};
const DataDisplay = ({ data }) => (
<div className="data">{JSON.stringify(data)}</div>
);
const EnhancedDataDisplay = withLoading(DataDisplay);
6.2 渲染属性(Render Props)- React
一种技术,用于共享代码逻辑,通常配合 HOC 使用。
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = event => {
this.setState({ x: event.clientX, y: event.clientY });
};
render() {
return (
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
<MouseTracker render={({ x, y }) => (
<h1>The mouse position is ({x}, {y})</h1>
)} />
6.3 提供者模式(Provider Pattern)
基于 Context API,解决深层组件传递 props 的问题。
const ThemeContext = React.createContext();
class ThemeProvider extends React.Component {
state = { theme: 'light' };
toggleTheme = () => {
this.setState(prev => ({
theme: prev.theme === 'light' ? 'dark' : 'light'
}));
};
render() {
return (
<ThemeContext.Provider value={{ theme: this.state.theme, toggleTheme: this.toggleTheme }}>
{this.props.children}
</ThemeContext.Provider>
);
}
}
6.4 Vue 组合式函数(Composables)
import { ref, onMounted, onUnmounted } from 'vue';
export function useMouse() {
const x = ref(0);
const y = ref(0);
const update = event => {
x.value = event.pageX;
y.value = event.pageY;
};
onMounted(() => window.addEventListener('mousemove', update));
onUnmounted(() => window.removeEventListener('mousemove', update));
return { x, y };
}
七、设计模式选择指南
| 模式 | 适用场景 | 优点 | 缺点 |
|---|
| 工厂模式 | 需要创建多种类似对象 | 封装创建逻辑,易于扩展 | 增加系统复杂度 |
| 单例模式 | 全局唯一实例(配置、日志) | 节省内存,全局访问 | 测试困难,全局状态污染 |
| 观察者模式 | 一对多依赖关系 | 松耦合,易于扩展 | 可能引起内存泄漏 |
| 装饰器模式 | 动态添加功能 | 灵活,符合开放封闭原则 | 多层装饰复杂 |
| 策略模式 | 多种算法切换 | 避免条件语句,易于扩展 | 增加策略类数量 |
| 中间件模式 | 处理请求管道 | 关注点分离,易于测试 | 可能影响性能 |
八、最佳实践
- 不要过度设计:简单的代码往往比复杂的设计模式更好,按需引入。
- 模式组合使用:实际项目中经常组合多种模式来解决复杂问题。
- 考虑可测试性:设计模式应提高代码的可测试性,而非降低。
- 保持一致性:团队内统一使用某些模式,降低沟通成本。
- 文档化:对使用的设计模式进行说明,方便后续维护。
九、现代 JavaScript 中的新特性
9.1 Proxy 和 Reflect 实现模式
利用 Proxy 可以轻松实现数据绑定、验证等高级功能。
function createObservable(obj, callback) {
return new Proxy(obj, {
set(target, property, value) {
const oldValue = target[property];
target[property] = value;
callback(property, oldValue, value);
return true;
},
get(target, property) {
console.log(`Getting ${property}`);
return target[property];
}
});
}
const user = createObservable(
{ name: 'John', age: 30 },
(prop, oldVal, newVal) => {
console.log(`${prop} changed from ${oldVal} to ${newVal}`);
}
);
user.name = 'Jane';
9.2 使用 ES6+ 特性简化模式
Symbol 可用于实现真正的私有属性,Generator 可简化迭代逻辑。
const _private = Symbol('private');
class MyClass {
constructor() {
this[_private] = 'secret';
}
getSecret() {
return this[_private];
}
}
function* paginate(items, pageSize) {
for (let i = 0; i < items.length; i += pageSize) {
yield items.slice(i, i + pageSize);
}
}
const items = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (const page of paginate(items, 3)) {
console.log('Page:', page);
}
设计模式是解决常见问题的工具箱,理解它们有助于编写更优雅、可维护的代码。在实际开发中,灵活运用这些模式,能让你的前端工程更加健壮。
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- Gemini 图片去水印
基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online