前端设计模式

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

一、设计模式分类(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. 代理模式:需要控制访问或添加额外功能时

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

相关推荐
浩星2 小时前
css实现类似element官网的磨砂屏幕效果
前端·javascript·css
一只小风华~2 小时前
Vue.js 核心知识点全面解析
前端·javascript·vue.js
2022.11.7始学前端2 小时前
n8n第七节 只提醒重要的待办
前端·javascript·ui·n8n
SakuraOnTheWay2 小时前
React Grab实践 | 记一次与Cursor的有趣对话
前端·cursor
阿星AI工作室2 小时前
gemini3手势互动圣诞树保姆级教程来了!附提示词
前端·人工智能
徐小夕2 小时前
知识库创业复盘:从闭源到开源,这3个教训价值百万
前端·javascript·github
ZouZou老师2 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
xhxxx2 小时前
函数执行完就销毁?那闭包里的变量凭什么活下来!—— 深入 JS 内存模型
前端·javascript·ecmascript 6
StarkCoder2 小时前
求求你试试 DiffableDataSource!别再手算 indexPath 了(否则迟早崩)
前端
fxshy2 小时前
Cursor 前端Global Cursor Rules
前端·cursor