前端设计模式

设计模式是软件工程中解决常见问题的可复用方案。以下是主流设计模式分类及前端常用模式详解:

一、设计模式分类(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({ /* ... */ });
  }
};

四、选择设计模式的建议

  1. 单例模式:需要全局唯一实例时
  2. 观察者模式:需要松耦合的事件通信时
  3. 策略模式:有多种算法或策略需要动态切换时
  4. 装饰器模式:需要动态添加功能而不修改原对象时
  5. 工厂模式:创建逻辑复杂或需要批量创建时
  6. 代理模式:需要控制访问或添加额外功能时

记住:不要为了使用模式而使用模式,应根据实际问题和场景选择合适的模式。在小型项目中,过度设计反而会增加复杂度。

相关推荐
恋猫de小郭15 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment9 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端