设计模式是解决特定上下文中重复出现的问题的通用、可重用的解决方案模板,是软件工程领域的宝贵经验总结。
一、设计模式分类概览
创建型模式(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>六、反模式识别
常见反模式
上帝对象(God Object)
// ❌ 一个类做所有事情 class GodClass { validateUser() {} sendEmail() {} saveToDB() {} generateReport() {} processPayment() {} }重复代码
// ❌ 相同的代码出现在多个地方 function calculateTax1(amount) { return amount * 0.1 + amount * 0.05; } function calculateTax2(amount) { return amount * 0.1 + amount * 0.05; }过度设计
// ❌ 为简单的需求使用复杂的模式 // 不需要工厂模式的情况 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原则 // 自我检查问题: // - 这个模式是否解决了实际问题? // - 是否增加了不必要的复杂度? // - 是否符合团队的编码规范? // - 是否有更简单的解决方案?八、学习路径建议
初级阶段:掌握单例、工厂、观察者、策略
中级阶段:理解装饰器、适配器、模板方法、命令
高级阶段:应用组合、访问者、中介者、状态
精通阶段:识别模式组合,避免过度设计
总结
设计模式不是银弹,而是工具。正确的使用方式是:
理解问题本质,而不是生搬硬套
保持简单,在必要时引入复杂模式
关注原则,而不是具体实现
持续重构,让模式自然浮现
模式服务于代码,而不是代码服务于模式。好的设计应该让代码更清晰、更易维护,而不是更复杂。