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