设计模式是软件工程中解决常见问题的可复用方案。以下是主流设计模式分类及前端常用模式详解:
一、设计模式分类(23种经典模式)
创建型(5种)
- 工厂模式(Factory)
- 抽象工厂(Abstract Factory)
- 单例模式(Singleton)
- 建造者模式(Builder)
- 原型模式(Prototype)
结构型(7种)
- 适配器模式(Adapter)
- 装饰器模式(Decorator)
- 代理模式(Proxy)
- 外观模式(Facade)
- 桥接模式(Bridge)
- 组合模式(Composite)
- 享元模式(Flyweight)
行为型(11种)
- 观察者模式(Observer)
- 策略模式(Strategy)
- 状态模式(State)
- 责任链模式(Chain of Responsibility)
- 命令模式(Command)
- 迭代器模式(Iterator)
- 中介者模式(Mediator)
- 备忘录模式(Memento)
- 访问者模式(Visitor)
- 模板方法模式(Template Method)
- 解释器模式(Interpreter)
二、前端开发中常用的设计模式
1. 单例模式(Singleton)
场景:全局状态管理、对话框、缓存、日志工具
javascript
// Redux Store 就是单例模式的典型应用
class AppState {
constructor() {
if (AppState.instance) return AppState.instance;
this.state = {};
AppState.instance = this;
}
setState(key, value) {
this.state[key] = value;
}
getState(key) {
return this.state[key];
}
}
// 使用
const appState1 = new AppState();
const appState2 = new AppState();
console.log(appState1 === appState2); // true
// 实际应用:全局模态框
class Modal {
constructor() {
if (Modal.instance) return Modal.instance;
this.element = document.createElement('div');
// ...初始化逻辑
Modal.instance = this;
}
show() { /* ... */ }
hide() { /* ... */ }
}
2. 观察者/发布-订阅模式(Observer/Pub-Sub)
场景:事件系统、Vue/React响应式、跨组件通信
javascript
// 自定义事件系统
class EventEmitter {
constructor() {
this.events = {};
}
on(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
emit(event, ...args) {
if (this.events[event]) {
this.events[event].forEach(cb => cb(...args));
}
}
off(event, callback) {
if (this.events[event]) {
this.events[event] = this.events[event].filter(cb => cb !== callback);
}
}
}
// 使用示例
const emitter = new EventEmitter();
// 组件A订阅
emitter.on('user-login', (user) => {
console.log(`用户 ${user.name} 登录了`);
});
// 组件B触发
emitter.emit('user-login', { name: '张三', id: 123 });
// 实际应用:React/Vue的自定义事件总线
3. 工厂模式(Factory)
场景:创建复杂对象、UI组件创建、API请求工厂
javascript
// 组件工厂
class ComponentFactory {
static create(type, props) {
switch(type) {
case 'button':
return new Button(props);
case 'input':
return new Input(props);
case 'modal':
return new Modal(props);
default:
throw new Error('未知组件类型');
}
}
}
class Button {
constructor(props) {
this.text = props.text;
this.onClick = props.onClick;
}
render() {
const button = document.createElement('button');
button.textContent = this.text;
button.addEventListener('click', this.onClick);
return button;
}
}
// 使用
const submitBtn = ComponentFactory.create('button', {
text: '提交',
onClick: () => console.log('提交表单')
});
// 实际应用:请求工厂
class RequestFactory {
static create(type) {
const strategies = {
'get': GetRequest,
'post': PostRequest,
'put': PutRequest,
'delete': DeleteRequest
};
return new strategies[type]();
}
}
4. 策略模式(Strategy)
场景:表单验证、支付方式选择、算法替换
javascript
// 表单验证策略
const validationStrategies = {
required: (value) => {
return value !== undefined && value !== null && value !== '';
},
email: (value) => {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
},
minLength: (value, length) => {
return value.length >= length;
},
maxLength: (value, length) => {
return value.length <= length;
}
};
class Validator {
constructor(strategies) {
this.strategies = strategies;
this.errors = [];
}
validate(field, rules) {
rules.forEach(rule => {
const [strategy, ...args] = rule.split(':');
if (!this.strategies[strategy](field, ...args)) {
this.errors.push(`${strategy} 验证失败`);
}
});
return this.errors;
}
}
// 使用
const validator = new Validator(validationStrategies);
const result = validator.validate('test@email.com', ['required', 'email']);
console.log(result); // []
// 实际应用:支付策略
const paymentStrategies = {
alipay: (amount) => { /* 支付宝支付逻辑 */ },
wechat: (amount) => { /* 微信支付逻辑 */ },
creditCard: (amount) => { /* 信用卡支付逻辑 */ }
};
function processPayment(method, amount) {
return paymentStrategies[method](amount);
}
5. 装饰器模式(Decorator)
场景:高阶组件、功能增强、AOP编程
javascript
// ES7装饰器语法
function logger(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function(...args) {
console.log(`调用 ${name},参数:`, args);
const result = original.apply(this, args);
console.log(`调用 ${name} 结果:`, result);
return result;
};
return descriptor;
}
class API {
@logger
fetchData(url) {
return fetch(url).then(res => res.json());
}
}
// 传统方式:高阶函数装饰器
function withLoadingIndicator(WrappedComponent) {
return class extends React.Component {
render() {
if (this.props.loading) {
return <div>加载中...</div>;
}
return <WrappedComponent {...this.props} />;
}
};
}
// 实际应用:React高阶组件
const EnhancedComponent = withLoadingIndicator(MyComponent);
6. 代理模式(Proxy)
场景:图片懒加载、缓存代理、权限控制
javascript
// ES6 Proxy实现图片懒加载
class LazyImage {
constructor(placeholder) {
this.placeholder = placeholder;
this.images = new Map();
}
setImage(target, src) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = src;
observer.unobserve(img);
}
});
});
observer.observe(target);
}
createImage(src) {
const img = document.createElement('img');
img.src = this.placeholder;
img.dataset.src = src;
this.setImage(img, src);
return img;
}
}
// 使用
const lazyLoader = new LazyImage('/placeholder.jpg');
const image = lazyLoader.createImage('/real-image.jpg');
document.body.appendChild(image);
// 缓存代理示例
function createCacheProxy(fn) {
const cache = new Map();
return new Proxy(fn, {
apply(target, thisArg, args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('从缓存获取');
return cache.get(key);
}
console.log('计算新值');
const result = Reflect.apply(target, thisArg, args);
cache.set(key, result);
return result;
}
});
}
const expensiveCalculation = (n) => {
// 复杂计算
return n * 2;
};
const cachedCalc = createCacheProxy(expensiveCalculation);
console.log(cachedCalc(5)); // 计算新值 10
console.log(cachedCalc(5)); // 从缓存获取 10
7. 模块模式(Module Pattern)
场景:代码组织、命名空间管理、私有变量封装
javascript
// ES6模块模式
const UserModule = (() => {
// 私有变量
let users = [];
let currentUser = null;
// 私有方法
function validateUser(user) {
return user && user.name && user.email;
}
// 公有API
return {
addUser(user) {
if (validateUser(user)) {
users.push(user);
return true;
}
return false;
},
getUsers() {
return [...users]; // 返回副本
},
setCurrentUser(user) {
currentUser = user;
},
getCurrentUser() {
return currentUser;
}
};
})();
// 使用
UserModule.addUser({ name: 'Alice', email: 'alice@example.com' });
console.log(UserModule.getUsers());
// 实际应用:工具库封装
const Utils = (() => {
const formatDate = (date) => { /* ... */ };
const debounce = (fn, delay) => { /* ... */ };
const throttle = (fn, limit) => { /* ... */ };
return { formatDate, debounce, throttle };
})();
8. 状态模式(State)
场景:状态机、游戏角色状态、UI状态管理
javascript
// 订单状态机
class OrderState {
constructor(order) {
this.order = order;
}
next() {}
previous() {}
cancel() {}
}
class PendingState extends OrderState {
next() {
console.log('订单确认 → 处理中');
this.order.setState(this.order.processingState);
}
cancel() {
console.log('订单取消');
this.order.setState(this.order.cancelledState);
}
}
class ProcessingState extends OrderState {
next() {
console.log('处理完成 → 已发货');
this.order.setState(this.order.shippedState);
}
previous() {
console.log('退回待处理状态');
this.order.setState(this.order.pendingState);
}
}
class Order {
constructor() {
this.pendingState = new PendingState(this);
this.processingState = new ProcessingState(this);
this.shippedState = new ShippedState(this);
this.cancelledState = new CancelledState(this);
this.state = this.pendingState;
}
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(); // 处理完成 → 已发货
9. 组合模式(Composite)
场景:UI组件树、文件系统、菜单系统
javascript
// UI组件系统
class Component {
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(`渲染 ${this.name}`);
this.children.forEach(child => child.render());
}
}
// 使用
const root = new Component('页面');
const header = new Component('头部');
const main = new Component('主体');
const footer = new Component('底部');
const menu = new Component('菜单');
const content = new Component('内容');
header.add(menu);
main.add(content);
root.add(header);
root.add(main);
root.add(footer);
root.render();
/*
渲染 页面
渲染 头部
渲染 菜单
渲染 主体
渲染 内容
渲染 底部
*/
三、现代前端框架中的设计模式
React中的模式:
javascript
// 1. 容器组件与展示组件模式
const UserListContainer = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchUsers().then(setUsers);
}, []);
return <UserList users={users} />;
};
// 展示组件
const UserList = ({ users }) => (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
// 2. 自定义Hook(策略+工厂)
const useLocalStorage = (key, initialValue) => {
const [storedValue, setStoredValue] = useState(() => {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
});
const setValue = (value) => {
setStoredValue(value);
localStorage.setItem(key, JSON.stringify(value));
};
return [storedValue, setValue];
};
Vue中的模式:
javascript
// 1. 混入模式(Mixins)
const logMixin = {
created() {
console.log(`${this.$options.name} 组件已创建`);
},
methods: {
log(message) {
console.log(`[${this.$options.name}]: ${message}`);
}
}
};
// 2. 插件模式(单例+装饰器)
const MyPlugin = {
install(Vue, options) {
// 添加全局方法或属性
Vue.prototype.$myMethod = function() { /* ... */ };
// 添加全局指令
Vue.directive('focus', { /* ... */ });
// 添加实例方法
Vue.mixin({ /* ... */ });
}
};
四、选择设计模式的建议
- 单例模式:需要全局唯一实例时
- 观察者模式:需要松耦合的事件通信时
- 策略模式:有多种算法或策略需要动态切换时
- 装饰器模式:需要动态添加功能而不修改原对象时
- 工厂模式:创建逻辑复杂或需要批量创建时
- 代理模式:需要控制访问或添加额外功能时
记住:不要为了使用模式而使用模式,应根据实际问题和场景选择合适的模式。在小型项目中,过度设计反而会增加复杂度。