跳到主要内容前端设计模式深度解析与实战 | 极客日志JavaScript大前端算法
前端设计模式深度解析与实战
综述由AI生成前端设计模式涵盖创建型、结构型及行为型三大类,旨在解决常见架构问题。通过工厂、单例、观察者等具体案例,展示了如何提升代码的可维护性与扩展性。结合现代 ES6+ 特性与框架实践,提供了从理论到落地的完整参考。
日志猎手15 浏览 前端设计模式深度解析与实战
设计模式概述
什么是设计模式
设计模式是针对特定上下文中常见问题的可重用解决方案。在前端开发中,它们帮助我们构建更易于维护、扩展和复用的代码结构。
设计模式分类
- 创建型模式:处理对象创建机制,解耦实例化逻辑。
- 结构型模式:处理对象组合方式,形成更大的功能单元。
- 行为型模式:处理对象间的通信和责任分配,优化交互流程。
创建型模式
工厂模式(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
建造者模式(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());
单例模式(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);
原型模式(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';
const secondaryButton = baseButton.clone();
secondaryButton.styles.color = 'gray';
结构型模式
适配器模式(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);
装饰器模式(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());
代理模式(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();
image2.display();
外观模式(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();
组合模式(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');
const usernameInput = new Input('Username');
const passwordInput = new Input('Password');
const submitButton = new Button('Submit');
form.add(usernameInput);
form.add(passwordInput);
form.add(submitButton);
const panel = new UIComponent('Main Panel');
panel.add(form);
panel.render();
行为型模式
观察者模式(Observer Pattern)
对象间的一对多依赖关系,当一个对象状态改变时,所有依赖者都会收到通知。
class Observer {
update(data) {}
}
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 extends Observer {
constructor(name) {
super();
this.name = name;
}
update(data) {
console.log(`${this.name} received:`, data);
}
}
const newsPublisher = new Subject();
const ui1 = new UserInterface('Mobile App');
const ui2 = new UserInterface('Web Dashboard');
const ui3 = new UserInterface('Email Service');
newsPublisher.subscribe(ui1);
newsPublisher.subscribe(ui2);
newsPublisher.subscribe(ui3);
newsPublisher.notify('New product launched!');
newsPublisher.unsubscribe(ui2);
newsPublisher.notify('Special discount available!');
发布 - 订阅模式(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();
const logger = data => console.log(`[LOG] ${data}`);
const notifier = data => console.log(`[NOTIFY] ${data}`);
const analyzer = data => console.log(`[ANALYZE] ${JSON.stringify(data)}`);
bus.subscribe('user.login', logger);
bus.subscribe('user.login', notifier);
bus.subscribe('user.purchase', analyzer);
bus.publish('user.login', { username: 'john', time: new Date() });
bus.publish('user.purchase', { item: 'Book', price: 29.99 });
策略模式(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 PayPalPayment extends PaymentStrategy {
constructor(email) {
super();
this.email = email;
}
pay(amount) {
console.log(`Paid $${amount} with PayPal ${this.email}`);
}
}
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.addItem('Mouse', 40);
cart.setPaymentStrategy(new CreditCardPayment('1234-5678-9012-3456', '123'));
cart.checkout();
cart.addItem('Keyboard', 80);
cart.setPaymentStrategy(new PayPalPayment('[email protected]'));
cart.checkout();
状态模式(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');
}
previous() {
this.order.setState(new PendingState(this.order));
console.log('Order moved back to pending');
}
}
class ShippedState extends OrderState {
next() {
this.order.setState(new DeliveredState(this.order));
console.log('Order delivered');
}
previous() {
this.order.setState(new ProcessingState(this.order));
console.log('Order moved back to processing');
}
}
class DeliveredState extends OrderState {}
class CancelledState extends OrderState {}
class Order {
constructor() {
this.state = new PendingState(this);
}
setState(state) {
this.state = state;
}
next() {
this.state.next();
}
previous() {
this.state.previous();
}
cancel() {
this.state.cancel();
}
}
const order = new Order();
order.next();
order.next();
order.next();
const order2 = new Order();
order2.next();
order2.cancel();
命令模式(Command Pattern)
将请求封装为对象,支持撤销操作和解耦发送者与接收者。
class Command {
execute() {}
undo() {}
}
class LightOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOn();
}
undo() {
this.light.turnOff();
}
}
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();
const lightOn = new LightOnCommand(light);
remote.setCommand(lightOn);
remote.pressButton(0);
remote.pressUndo();
前端特定模式
模块模式(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;
},
getUser(id) {
return users.find(user => user.id === id);
},
getAllUsers() {
return [...users];
},
getUserCount() {
return userCount;
},
getPublicUserData(id) {
const user = this.getUser(id);
if (user) {
const { email, ...publicData } = user;
return publicData;
}
return null;
}
};
})();
const userId = UserModule.addUser('John', '[email protected]');
console.log(UserModule.getPublicUserData(userId));
混入模式(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);
}
};
const Validatable = Base => class extends Base {
validate() {
const errors = [];
if (this.requiredFields) {
this.requiredFields.forEach(field => {
if (!this[field]) {
errors.push(`${field} is required`);
}
});
}
return {
isValid: errors.length === 0,
errors
};
}
};
class Model {
constructor(data = {}) {
Object.assign(this, data);
}
save() {
console.log('Saving model...');
}
}
class User extends Serializable(Validatable(Loggable(Model))) {
constructor(data) {
super(data);
this.requiredFields = ['name', 'email'];
}
}
const user = new User({ name: 'John Doe', email: '[email protected]' });
user.log('Created user');
console.log(user.validate());
const json = user.serialize();
const user2 = User.deserialize(json);
中间件模式(Middleware Pattern)
处理请求的管道,常用于框架如 Koa/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`);
});
pipeline.use(async (ctx, next) => {
console.log('Middleware 2: Authentication');
ctx.user = { id: 1, name: 'John' };
await next();
});
pipeline.use(async (ctx, next) => {
console.log('Middleware 3: Authorization');
if (!ctx.user) throw new Error('Unauthorized');
await next();
});
async function finalHandler(ctx) {
console.log('Final handler: Processing request');
console.log('User:', ctx.user);
ctx.response = { success: true, data: 'Some data' };
}
const context = { request: { url: '/api/data' } };
pipeline.execute(context, finalHandler).then(() => console.log('Response:', context.response)).catch(err => console.error('Error:', err.message));
组件模式(Component Pattern)
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);
}
render() {
throw new Error('render() must be implemented');
}
mount(container) {
this.container = container;
this.render();
}
}
class Button extends Component {
constructor(props) {
super(props);
this.state = { clicked: false };
}
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.style.color = 'white';
button.style.padding = '10px 20px';
button.onclick = this.handleClick;
if (this.container) {
this.container.innerHTML = '';
this.container.appendChild(button);
}
return button;
}
}
class Form extends Component {
render() {
const form = document.createElement('form');
form.style.padding = '20px';
form.style.border = '1px solid #ccc';
this.children.forEach(child => {
const element = child.render();
form.appendChild(element);
});
if (this.container) {
this.container.innerHTML = '';
this.container.appendChild(form);
}
return form;
}
}
const submitButton = new Button({ label: 'Submit', onClick: () => console.log('Submitted!') });
const cancelButton = new Button({ label: 'Cancel', onClick: () => console.log('Cancelled!') });
const form = new Form();
form.addChild(submitButton);
form.addChild(cancelButton);
form.mount(document.getElementById('app'));
React/Vue 中的设计模式
高阶组件(HOC)- React
const withLoading = WrappedComponent => {
return function WithLoadingComponent({ isLoading, ...props }) {
if (isLoading) {
return <div className="loading">Loading...</div>;
}
return <WrappedComponent {...props} />;
};
};
const withError = WrappedComponent => {
return function WithErrorComponent({ error, ...props }) {
if (error) {
return <div className="error">Error: {error.message}</div>;
}
return <WrappedComponent {...props} />;
};
};
const DataDisplay = ({ data }) => (
<div className="data">{JSON.stringify(data)}</div>
);
const EnhancedDataDisplay = withError(withLoading(DataDisplay));
<EnhancedDataDisplay isLoading={loading} error={error} data={data} />
渲染属性(Render Props)- React
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>
)} />
提供者模式(Provider Pattern)
React Context API 的核心思想,用于跨层级传递数据。
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>
);
}
}
const ThemedButton = () => (
<ThemeContext.Consumer>
{({ theme, toggleTheme }) => (
<button
style={{
backgroundColor: theme === 'dark' ? '#333' : '#fff',
color: theme === 'dark' ? '#fff' : '#333'
}}
onClick={toggleTheme}
>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
Vue 组合式函数(Composables)
Vue 3 Composition API 中的逻辑复用模式。
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 };
}
import { ref } from 'vue';
export function useFetch(url) {
const data = ref(null);
const error = ref(null);
const loading = ref(false);
const fetchData = async () => {
loading.value = true;
try {
const response = await fetch(url);
data.value = await response.json();
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
};
fetchData();
return { data, error, loading, refetch: fetchData };
}
设计模式选择指南
| 模式 | 适用场景 | 优点 | 缺点 |
|---|
| 工厂模式 | 需要创建多种类似对象 | 封装创建逻辑,易于扩展 | 增加系统复杂度 |
| 单例模式 | 全局唯一实例(配置、日志) | 节省内存,全局访问 | 测试困难,全局状态污染 |
| 观察者模式 | 一对多依赖关系 | 松耦合,易于扩展 | 可能引起内存泄漏 |
| 装饰器模式 | 动态添加功能 | 灵活,符合开放封闭原则 | 多层装饰复杂 |
| 策略模式 | 多种算法切换 | 避免条件语句,易于扩展 | 增加策略类数量 |
| 中间件模式 | 处理请求管道 | 关注点分离,易于测试 | 可能影响性能 |
最佳实践
- 不要过度设计:简单的代码比复杂的设计模式更好,按需引入。
- 模式组合使用:实际项目中经常组合多种模式来解决复杂问题。
- 考虑可测试性:设计模式应提高代码的可测试性,而非降低。
- 保持一致性:团队内统一使用某些模式,降低沟通成本。
- 文档化:对使用的设计模式进行文档说明,方便后续维护。
现代 JavaScript 中的新特性
Proxy 和 Reflect 实现模式
利用 ES6 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';
使用 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