设计模式详解:代码架构的艺术

设计模式是解决特定上下文中重复出现的问题的通用、可重用的解决方案模板,是软件工程领域的宝贵经验总结。

一、设计模式分类概览

创建型模式(5种):对象创建的艺术

  • 单例模式:确保一个类只有一个实例

  • 工厂方法:创建对象但不指定具体类

  • 抽象工厂:创建相关对象家族

  • 建造者:分步构建复杂对象

  • 原型:通过复制创建对象

结构型模式(7种):对象组合的艺术

  • 适配器:兼容不同接口

  • 装饰器:动态添加功能

  • 代理:控制对象访问

  • 外观:简化复杂子系统

  • 桥接:分离抽象与实现

  • 组合:树形结构处理

  • 享元:共享小对象节省内存

行为型模式(11种):对象交互的艺术

  • 策略:封装可互换的算法

  • 观察者:一对多的依赖关系

  • 模板方法:定义算法骨架

  • 迭代器:顺序访问集合元素

  • 责任链:传递请求的链

  • 命令:封装请求为对象

  • 备忘录:保存和恢复状态

  • 状态:封装状态相关行为

  • 访问者:分离算法与结构

  • 中介者:减少对象间耦合

  • 解释器:定义语言文法

二、设计原则(SOLID)

1. 单一职责原则(SRP)

复制代码
// ❌ 违反SRP - 一个类承担多个职责
class UserManager {
  createUser(user) {
    // 验证逻辑
    // 保存到数据库
    // 发送欢迎邮件
    // 更新统计信息
  }
}

// ✅ 遵守SRP - 每个类只有一个职责
class UserValidator {
  validate(user) { /* 验证逻辑 */ }
}

class UserRepository {
  save(user) { /* 数据库操作 */ }
}

class EmailService {
  sendWelcome(user) { /* 发送邮件 */ }
}

class StatisticsService {
  update(user) { /* 更新统计 */ }
}

2. 开闭原则(OCP)

复制代码
// ✅ 对扩展开放,对修改关闭
class Discount {
  getDiscount(amount) {
    return amount * 0.1; // 默认10%折扣
  }
}

class PremiumDiscount extends Discount {
  getDiscount(amount) {
    return amount * 0.2; // 高级用户20%折扣
  }
}

class VIPDiscount extends Discount {
  getDiscount(amount) {
    return amount * 0.3; // VIP用户30%折扣
  }
}

// 新增折扣类型时不需要修改现有代码
class BlackFridayDiscount extends Discount {
  getDiscount(amount) {
    return amount * 0.5; // 黑五50%折扣
  }
}

3. 里氏替换原则(LSP)

复制代码
// ✅ 子类可以替换父类
class Bird {
  move() { console.log('移动'); }
}

class FlyingBird extends Bird {
  fly() { console.log('飞行'); }
}

class Penguin extends Bird {
  move() { console.log('游泳'); } // 企鹅用游泳替代移动
}

function makeBirdMove(bird) {
  bird.move(); // 可以传入任何Bird子类
}

4. 接口隔离原则(ISP)

复制代码
// ❌ 违反ISP - 臃肿的接口
interface Worker {
  work();
  eat();
  sleep();
}

// ✅ 遵守ISP - 细分的接口
interface Workable {
  work();
}

interface Eatable {
  eat();
}

interface Sleepable {
  sleep();
}

class Human implements Workable, Eatable, Sleepable {
  work() { /* 工作 */ }
  eat() { /* 吃饭 */ }
  sleep() { /* 睡觉 */ }
}

class Robot implements Workable {
  work() { /* 工作 */ }
}

5. 依赖倒置原则(DIP)

复制代码
// ✅ 依赖抽象,而不是具体实现
// 抽象层
interface Database {
  save(data);
}

// 具体实现
class MySQLDatabase implements Database {
  save(data) { /* MySQL实现 */ }
}

class MongoDB implements Database {
  save(data) { /* MongoDB实现 */ }
}

// 高层模块依赖抽象
class UserService {
  constructor(database: Database) {
    this.database = database;
  }
  
  createUser(user) {
    // 业务逻辑...
    this.database.save(user);
  }
}

三、模式选择决策树

复制代码

四、关键模式详解

1. 工厂方法模式

复制代码
// 产品接口
class Transport {
  deliver() {}
}

// 具体产品
class Truck extends Transport {
  deliver() {
    return "陆路运输";
  }
}

class Ship extends Transport {
  deliver() {
    return "海运";
  }
}

// 创建者
class Logistics {
  planDelivery() {
    const transport = this.createTransport();
    console.log(`计划: ${transport.deliver()}`);
  }
  
  createTransport() {
    throw new Error("必须实现");
  }
}

// 具体创建者
class RoadLogistics extends Logistics {
  createTransport() {
    return new Truck();
  }
}

class SeaLogistics extends Logistics {
  createTransport() {
    return new Ship();
  }
}

// 使用
const roadLogistics = new RoadLogistics();
roadLogistics.planDelivery(); // 输出: 计划: 陆路运输

2. 观察者模式

复制代码
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 Observer {
  update(data) {}
}

// 具体实现
class NewsPublisher extends Subject {
  publish(news) {
    console.log(`发布新闻: ${news}`);
    this.notify(news);
  }
}

class Subscriber extends Observer {
  constructor(name) {
    super();
    this.name = name;
  }
  
  update(news) {
    console.log(`${this.name} 收到新闻: ${news}`);
  }
}

// 使用
const publisher = new NewsPublisher();
const subscriber1 = new Subscriber("用户A");
const subscriber2 = new Subscriber("用户B");

publisher.subscribe(subscriber1);
publisher.subscribe(subscriber2);

publisher.publish("今日头条新闻");

3. 装饰器模式

复制代码
class Coffee {
  cost() {
    return 5;
  }
  
  description() {
    return "普通咖啡";
  }
}

class CoffeeDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }
  
  cost() {
    return this.coffee.cost();
  }
  
  description() {
    return this.coffee.description();
  }
}

class MilkDecorator extends CoffeeDecorator {
  cost() {
    return this.coffee.cost() + 2;
  }
  
  description() {
    return this.coffee.description() + " + 牛奶";
  }
}

class SugarDecorator extends CoffeeDecorator {
  cost() {
    return this.coffee.cost() + 1;
  }
  
  description() {
    return this.coffee.description() + " + 糖";
  }
}

// 使用
let myCoffee = new Coffee();
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`);

myCoffee = new MilkDecorator(myCoffee);
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`);

myCoffee = new SugarDecorator(myCoffee);
console.log(`${myCoffee.description()}: $${myCoffee.cost()}`);

4. 策略模式

复制代码
class PaymentStrategy {
  pay(amount) {}
}

class CreditCardPayment extends PaymentStrategy {
  constructor(cardNumber) {
    super();
    this.cardNumber = cardNumber;
  }
  
  pay(amount) {
    console.log(`信用卡支付 $${amount}`);
  }
}

class PayPalPayment extends PaymentStrategy {
  constructor(email) {
    super();
    this.email = email;
  }
  
  pay(amount) {
    console.log(`PayPal支付 $${amount}`);
  }
}

class ShoppingCart {
  constructor() {
    this.items = [];
    this.paymentStrategy = null;
  }
  
  setPaymentStrategy(strategy) {
    this.paymentStrategy = strategy;
  }
  
  checkout() {
    const total = this.items.reduce((sum, item) => sum + item.price, 0);
    this.paymentStrategy.pay(total);
  }
}

5. 单例模式

复制代码
// 懒汉式单例
class Logger {
  constructor() {
    if (Logger.instance) {
      return Logger.instance;
    }
    this.logs = [];
    Logger.instance = this;
    return this;
  }
  
  log(message) {
    const timestamp = new Date().toISOString();
    this.logs.push(`${timestamp}: ${message}`);
    console.log(message);
  }
  
  getLogs() {
    return this.logs;
  }
}

// 使用
const logger1 = new Logger();
const logger2 = new Logger();

logger1.log("第一条日志");
logger2.log("第二条日志");

console.log(logger1 === logger2); // true
console.log(logger1.getLogs()); // 包含两条日志

五、设计模式应用场景

Web开发中的应用

复制代码
// React Hooks中的状态管理(观察者模式)
const [state, setState] = useState(initialState);

// Redux中的状态管理(单例+观察者)
const store = createStore(reducer);
store.subscribe(() => {
  const state = store.getState();
  // 更新UI
});

// Express中间件(责任链模式)
app.use((req, res, next) => {
  // 认证中间件
  next();
});

app.use((req, res, next) => {
  // 日志中间件
  next();
});

// Vue/React组件(组合模式)
<App>
  <Header />
  <Main>
    <Sidebar />
    <Content />
  </Main>
  <Footer />
</App>

六、反模式识别

常见反模式

  1. 上帝对象(God Object)

    复制代码
    // ❌ 一个类做所有事情
    class GodClass {
      validateUser() {}
      sendEmail() {}
      saveToDB() {}
      generateReport() {}
      processPayment() {}
    }
  2. 重复代码

    复制代码
    // ❌ 相同的代码出现在多个地方
    function calculateTax1(amount) {
      return amount * 0.1 + amount * 0.05;
    }
    
    function calculateTax2(amount) {
      return amount * 0.1 + amount * 0.05;
    }
  3. 过度设计

    复制代码
    // ❌ 为简单的需求使用复杂的模式
    // 不需要工厂模式的情况
    class SimpleObjectFactory {
      createObject(type) {
        switch(type) {
          case 'A': return new A();
          case 'B': return new B();
          default: return new Default();
        }
      }
    }

七、实践建议

何时使用设计模式?

场景 推荐模式 原因
需要全局访问点 单例模式 如配置管理、日志记录
需要创建复杂对象 建造者模式 如SQL查询构建器
需要不同算法策略 策略模式 如支付方式、排序算法
需要事件通知 观察者模式 如状态变更通知
需要动态添加功能 装饰器模式 如中间件、权限验证
需要简化复杂系统 外观模式 如API封装、SDK设计

代码质量检查清单

复制代码
// 好的设计模式应用应该:
// 1. 提高代码可读性
// 2. 降低耦合度
// 3. 提高可测试性
// 4. 便于扩展和维护
// 5. 遵循SOLID原则

// 自我检查问题:
// - 这个模式是否解决了实际问题?
// - 是否增加了不必要的复杂度?
// - 是否符合团队的编码规范?
// - 是否有更简单的解决方案?

八、学习路径建议

  1. 初级阶段:掌握单例、工厂、观察者、策略

  2. 中级阶段:理解装饰器、适配器、模板方法、命令

  3. 高级阶段:应用组合、访问者、中介者、状态

  4. 精通阶段:识别模式组合,避免过度设计

总结

设计模式不是银弹,而是工具。正确的使用方式是:

  • 理解问题本质,而不是生搬硬套

  • 保持简单,在必要时引入复杂模式

  • 关注原则,而不是具体实现

  • 持续重构,让模式自然浮现

模式服务于代码,而不是代码服务于模式。好的设计应该让代码更清晰、更易维护,而不是更复杂。

相关推荐
半桶水专家3 小时前
vue3中v-model 用法详解
前端·javascript·vue.js
行走的陀螺仪3 小时前
Vue3 项目单元测试全指南:价值、Vitest 落地与提效方案
开发语言·前端·单元测试·html5·vitest
亿坊电商3 小时前
在搭建PHP框架时如何优雅处理错误与异常?
开发语言·php·代码规范
❥ღ Komo·5 小时前
K8s1.28.15网络插件Calico全解析
开发语言·php
❥ღ Komo·5 小时前
K8s服务发现与DNS解析全解析
java·开发语言
FuckPatience5 小时前
C# 项目调试的时候进不去断点
开发语言·c#
元亓亓亓5 小时前
考研408--组成原理--day8--汇编指令&不同语句的机器级表示
开发语言·汇编·c#
醇氧11 小时前
【Windows】优雅启动:解析一个 Java 服务的后台启动脚本
java·开发语言·windows
2401_8784545311 小时前
浏览器工作原理
前端·javascript