设计模式基础
设计模式是软件设计中常见问题的典型解决方案,是代码设计经验的总结与抽象。
什么是设计模式
设计模式是经过验证的、可复用的代码设计方案,描述了在特定环境下解决软件设计问题的方案。
设计模式三要素
- 模式名称:简洁描述模式特点
- 问题:描述模式应用的场景
- 解决方案:描述模式的组成与实现
设计模式分类
三大类型
| 类型 | 说明 | 典型模式 |
|---|---|---|
| 创建型 | 对象创建机制 | 单例、工厂、建造者、原型 |
| 结构型 | 对象组合方式 | 代理、装饰器、适配器、外观 |
| 行为型 | 对象通信方式 | 观察者、策略、命令、迭代器 |
设计原则(SOLID)
单一职责原则(SRP)
一个类只负责一个职责,只有一个引起变化的原因。
JavaScript
// 不好的设计:一个类承担多个职责
class User {
constructor(name) {
this.name = name;
}
getName() { return this.name; }
save() { /* 保存到数据库 */ }
sendEmail() { /* 发送邮件 */ }
}
// 好的设计:职责分离
class User {
constructor(name) {
this.name = name;
}
getName() { return this.name; }
}
class UserRepository {
save(user) { /* 保存到数据库 */ }
}
class EmailService {
send(user, message) { /* 发送邮件 */ }
}
开闭原则(OCP)
对扩展开放,对修改关闭。
JavaScript
// 不好的设计:添加新类型需要修改原有代码
function calculateArea(shape) {
if (shape.type === 'circle') {
return Math.PI * shape.radius ** 2;
} else if (shape.type === 'rectangle') {
return shape.width * shape.height;
}
}
// 好的设计:通过扩展支持新类型
class Shape {
area() {
throw new Error('Must implement area');
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
area() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
area() {
return this.width * this.height;
}
}
// 添加新形状无需修改现有代码
class Triangle extends Shape {
area() { /* ... */ }
}
里氏替换原则(LSP)
子类必须能替换父类,且不影响程序正确性。
JavaScript
class Bird {
move() { return 'moving'; }
}
class Sparrow extends Bird {
move() { return 'flying'; }
}
class Penguin extends Bird {
move() { return 'walking'; } // 企鹅不会飞,但能移动
}
function makeBirdMove(bird) {
return bird.move(); // 任何Bird子类都可使用
}
接口隔离原则(ISP)
不应强迫依赖不使用的方法。
JavaScript
// 不好的设计:大接口
class Worker {
work() {}
eat() {}
sleep() {}
}
// 好的设计:接口分离
class Workable {
work() {}
}
class Eatable {
eat() {}
}
class HumanWorker {
work() { /* 实现 */ }
eat() { /* 实现 */ }
}
class RobotWorker {
work() { /* 实现 */ }
// Robot不需要eat
}
依赖倒置原则(DIP)
高层模块不依赖低层模块,都依赖抽象。
JavaScript
// 不好的设计:高层依赖低层
class Light {
turnOn() {}
turnOff() {}
}
class Switch {
constructor() {
this.light = new Light(); // 直接依赖具体实现
}
toggle() {
if (this.on) {
this.light.turnOff();
} else {
this.light.turnOn();
}
}
}
// 好的设计:依赖抽象
class Switch {
constructor(device) { // 依赖注入
this.device = device;
}
toggle() {
this.device.toggle();
}
}
class Light {
toggle() { /* ... */ }
}
class Fan {
toggle() { /* ... */ }
}
// 使用
const lightSwitch = new Switch(new Light());
const fanSwitch = new Switch(new Fan());
其他重要原则
迪米特法则(LoD)
一个对象应尽量少了解其他对象,又称最少知识原则。
JavaScript
// 不好的设计:链式调用过多
function getManagerName(employee) {
return employee.getDepartment().getManager().getName();
}
// 好的设计:封装内部结构
class Employee {
getManagerName() {
return this.department.getManagerName();
}
}
合成复用原则(CRP)
优先使用组合而非继承。
JavaScript
// 继承方式(不推荐)
class Animal {
move() { return 'moving'; }
}
class Dog extends Animal {
bark() { return 'barking'; }
}
// 组合方式(推荐)
class Mover {
move() { return 'moving'; }
}
class Barker {
bark() { return 'barking'; }
}
class Dog {
constructor() {
this.mover = new Mover();
this.barker = new Barker();
}
move() { return this.mover.move(); }
bark() { return this.barker.bark(); }
}
JavaScript常用模式
模块模式
JavaScript
const Module = (function () {
let private = 'private';
function privateMethod() {
return private;
}
return {
publicMethod() {
return privateMethod();
}
};
})();
策略模式
JavaScript
const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b
};
function calculate(strategy, a, b) {
return strategies[strategy](a, b);
}
命令模式
JavaScript
class Command {
execute() {}
undo() {}
}
class LightOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.on();
}
undo() {
this.light.off();
}
}
要点总结
- 三大类型:创建型、结构型、行为型
- SOLID原则:单一职责、开闭、里氏替换、接口隔离、依赖倒置
- 组合优于继承:提高灵活性,减少耦合
- 依赖抽象:面向接口编程,降低耦合度
- 实际应用:根据具体场景选择合适模式,避免过度设计
存放路径:articles/JS/专家/设计模式与架构思想/设计模式基础.md
📝 发现内容有误?点击此处直接编辑