六大设计原则
1. 单一职责原则(SRP)
Single Responsibility Principle
一个类应该只有一个引起它变化的原因。
// 不推荐:用户即可获取用户信息和发送邮件
class UserService {
getName() { /* */ }
sendEmail(msg: string) { /* */ }
}
// 推荐:将职责分离
class UserService {
getName() { /* */ }
}
class EmailService {
sendEmail(msg: string) { /* */ }
}
2. 开放封闭原则(OCP)
Open/Closed Principle
对扩展开放,对修改封闭。
// 不遵循 OCP 的设计
class AreaCalculator {
calculate(shape) {
if (shape.type === 'circle') {
console.log(Math.PI * shape.radius ** 2);
} else if (shape.type === 'rectangle') {
console.log(shape.width * shape.height);
}
// 每增加一种新图形,就要修改这个方法!
}
}
// 图形接口
interface Shape {
calculateArea(): number;
}
// 圆形
class Circle implements Shape {
constructor(public radius: number) {}
calculateArea(): number {
return Math.PI * this.radius ** 2;
}
}
// 矩形
class Rectangle implements Shape {
constructor(public width: number, public height: number) {}
calculateArea(): number {
return this.width * this.height;
}
}
//计算打印
class AreaCalculator {
calculate(shapes: Shape) {
console.log(shape.calculateArea())
}
}
let circle = new Circle(10)
let rectangle = new Rectangle(10,20)
new AreaCalculator().calculate(circle)
new AreaCalculator().calculate(rectangle)
3. 里氏替换原则(LSP)
Liskov Substitution Principle
子类必须能够替换父类,并保持行为一致。
// 不推荐:子类行为违背父类预期
class Bird {
fly() {
console.log('Flying');
}
}
class Penguin extends Bird {
fly() {
throw new Error("Penguins can't fly");
}
}
// 推荐:重新组织类结构
class Animal {}
class FlyingBird extends Animal {
fly() {
console.log('Flying');
}
}
class PenguinV2 extends Animal {
swim() {
console.log('Swimming');
}
}
4. 接口隔离原则(ISP)
Interface Segregation Principle
不要强迫依赖它不需要的接口。和单一职责类似
// 臃肿的接口
interface Worker {
void work();
void eat();
void sleep();
}
// 机器人不需要“eat”和“sleep”
class Robot implements Worker {
@Override
public void work() { System.out.println("机器人工作"); }
@Override
public void eat() { /* 机器人不需要吃 */ }
@Override
public void sleep() { /* 机器人不需要睡觉 */ }
}
// 推荐
// 拆分成多个小接口
interface Workable {
void work();
}
interface Eatable {
void eat();
}
interface Sleepable {
void sleep();
}
// 机器人只实现Workable
class Robot implements Workable {
@Override
public void work() { System.out.println("机器人工作"); }
}
5. 依赖倒置原则(DIP)
Dependency Inversion Principle
高层模块不应该依赖低层模块实例,而应该依赖抽象。
// 不推荐:依赖具体的水果存储方式
class LocalStorage {
save(fruit: any) {
console.log('Saved to local storage');
}
}
class FruitApp {
storage = new LocalStorage();
saveFruit(fruit: any) {
this.storage.save(fruit);
}
}
// 推荐:依赖抽象接口
interface Storage {
save(fruit: any): void;
}
class LocalStorageV2 implements Storage {
save(fruit: any) {
console.log('Saved to local storage');
}
}
class CloudStorage implements Storage {
save(fruit: any) {
console.log('Saved to cloud');
}
}
class FruitAppV2 {
constructor(private storage: Storage) {}
saveFruit(fruit: any) {
this.storage.save(fruit);
}
}
6. 迪米特法则 (LOD)
Law of Demeter
最少知道原则 一个对象应该对其他对象有尽可能少的了解,只与“直接的朋友”通信。 不要对象调用对象再调用属性。
// 不推荐:多个对象链式调用
// Department 类
class Department {
private company: Company;
constructor(company: Company) {
this.company = company;
}
public getCompany(): Company {
return this.company;
}
}
// Company 类
class Company {
private name: string;
constructor(name: string) {
this.name = name;
}
public getName(): string {
return this.name;
}
}
// Person 类
class Person {
private department: Department;
constructor(department: Department) {
this.department = department;
}
public getDepartment(): Department {
return this.department;
}
}
// Client 直接进行链式调用,依赖了 Person -> Department -> Company 的内部结构
const getCompanyName = () => {
const company = new Company("Acme Corp");
const department = new Department(company);
const person = new Person(department);
// 链式调用,如果中间任何一环变化,这里就会出错
const companyName = person.getDepartment().getCompany().getName();
console.log(companyName); // 输出: Acme Corp
};
getCompanyName();
// 推荐
// Person 类
class Person {
private department: Department;
constructor(department: Department) {
this.department = department;
}
// 提供一个高层方法,封装内部细节,Client 不需要知道 Department 和 Company
public getCompanyName(): string {
return this.department.getCompany().getName();
}
}
// Client 只与 Person 打交道,不关心内部的 Department 和 Company
const getCompanyName = () => {
const company = new Company("Acme Corp");
const department = new Department(company);
const person = new Person(department);
// 只调用 Person 提供的方法,不涉及内部结构
const companyName = person.getCompanyName();
console.log(companyName); // 输出: Acme Corp
};
getCompanyName();
23 种设计模式
设计模式分为三大类:创建型、结构型、行为型。
一、创建型模式
关注对象的创建方式。
1. 单例模式(Singleton)
确保一个类只有一个实例,并提供全局访问点。 控制实例数量,全局共享。
class Singleton {
static instance:any;
constructor() {
if (Singleton.instance) return Singleton.instance;
Singleton.instance = this;
}
}
const a = new Singleton();
const b = new Singleton();
console.log(a === b); // true
2. 工厂方法模式(Factory Method)
不直接new,而是通过工厂生产
// 定义 Car 类,并为属性添加类型
class Car {
model: string; // 明确 model 是字符串类型
constructor(model: string) { // 构造函数参数也明确类型
this.model = model;
}
}
// 定义 CarFactory 类
class CarFactory {
// 方法接收一个 string 类型的 model 参数,返回一个 Car 实例
createCar(model: string): Car {
return new Car(model);
}
}
// 使用
const factory = new CarFactory();
const carA = factory.createCar('Toyota');
console.log(carA.model); // 输出: Toyota
3. 抽象工厂模式(Abstract Factory)
提供一个接口,用于创建相关或依赖对象的家族,而无需指定具体类。 创建一组相关对象。
interface Button {
render(): void;
}
interface Checkbox {
render(): void;
}
class WinButton implements Button {
render() { console.log("Windows按钮"); }
}
class MacButton implements Button {
render() { console.log("Mac按钮"); }
}
class WinCheckbox implements Checkbox {
render() { console.log("WinCheckbox"); }
}
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WinFactory implements GUIFactory {
createButton() { return new WinButton(); }
createCheckbox() { return new WinCheckbox(); } // 假设有WinCheckbox
}
// 使用:
const factory = new WinFactory();
factory.createButton().render();
factory.createCheckbox().render();
4. 建造者模式(Builder)
分步骤构建复杂对象,灵活组合。
class BurgerBuilder {
constructor() { this.burger = {}; }
addLettuce() { this.burger.lettuce = true; return this; }
addCheese() { this.burger.cheese = true; return this; }
build() { return this.burger; }
}
const burger = new BurgerBuilder().addLettuce().addCheese().build();
console.log(burger);
5. 原型模式(Prototype)
通过复制现有对象来创建新对象,而不是新建实例。 克隆对象,避免重复初始化。
const vehicle = {
wheels: 4,
start() { console.log('Starting...'); }
};
const car = Object.create(vehicle);
car.color = 'red';
console.log(car.wheels); // 4
二、结构型模式
关注类和对象的组合方式。
6. 适配器模式(Adapter)
例子1:电压转化
美国电器110V,中国220V,就要有一个变压器将110V转化为220V
将一个类的接口转换成期望的另一个接口
// 定义V110Power类
class V110Power {
supplyPower() {
console.log("V110Power提供110V电源");
return "110V电源";
}
}
// 定义V220Power类(目标接口)
class V220Power {
providePower() {
console.log("V220Power提供220V电源");
return "220V电源";
}
}
// 定义适配器类,将V110Power适配为V220Power
class V220PowerAdapter extends V220Power {
constructor(v110Power) {
super(); // 调用父类构造函数
this.v110Power = v110Power;
}
// 重写providePower方法,内部调用v110Power的supplyPower方法
providePower() {
console.log("适配器正在将110V电源转换为220V电源...");
const power = this.v110Power.supplyPower();
// 这里可以添加实际的转换逻辑(在现实中可能是变压器等)
console.log(`将${power}转换为220V电源`);
return "220V电源"; // 返回适配后的电源
}
}
// 定义ChinaDevice类
class ChinaDevice {
inputPower(power) {
// 这里处理输入的电源
console.log("ChinaDevice接收到了电源:", power.constructor.name);
const powerProvided = power.providePower(); // 调用提供电源的方法
console.log("设备正在使用:", powerProvided);
// 实际应用中可能会有更多处理逻辑
}
}
// 使用示例
const chinaDevice = new ChinaDevice();
const v110Power = new V110Power();
const v220PowerAdapter = new V220PowerAdapter(v110Power); // 创建适配器
chinaDevice.inputPower(v220PowerAdapter); // 传入适配后的电源
例子2:第三方支持接口统一
// 第三方支付类:PayPal
class PayPal {
makePayment(amountInUSD) {
console.log(`使用 PayPal 支付了 ${amountInUSD} 美元`);
}
}
// 第三方支付类:Stripe
class Stripe {
charge(amountInCents) {
console.log(`使用 Stripe 支付了 ${amountInCents / 100} 美元`);
}
}
上面PayPal 和 Stripe支付的接口为单位都不一样
// 目标接口:统一的支付接口
class Payment {
pay(amount) {
throw new Error("该方法需要在子类中实现");
}
}
// PayPal 适配器
class PayPalAdapter extends Payment {
constructor(paypal) {
super();
this.paypal = paypal;
}
pay(amountInDollars) {
// 将美元传给 PayPal 的 makePayment 方法
this.paypal.makePayment(amountInDollars);
}
}
// Stripe 适配器
class StripeAdapter extends Payment {
constructor(stripe) {
super();
this.stripe = stripe;
}
pay(amountInDollars) {
// 将美元转换为美分(1美元 = 100美分)
const amountInCents = amountInDollars * 100;
this.stripe.charge(amountInCents);
}
}
// 客户端使用------
// 创建第三方支付实例
const paypal = new PayPal();
const stripe = new Stripe();
// 创建适配器实例
const paypalAdapter = new PayPalAdapter(paypal);
const stripeAdapter = new StripeAdapter(stripe);
// 使用适配后的支付接口进行支付
paypalAdapter.pay(100) // 使用 PayPal 支付 100 美元
stripeAdapter.pay(50) // 使用 Stripe 支付 50 美元
7. 桥接模式(Bridge)
将抽象部分与实现部分分离,使它们可以独立变化。 抽象与实现解耦。
把实例里面可以抽象的部分提取到抽象类。
class TV {
turnOn() { console.log('TV on'); }
}
class Remote {
constructor(device) { this.device = device; }
power() { this.device.turnOn(); }
}
const remote = new Remote(new TV());
remote.power();
8. 组合模式(Composite)
将对象组合成树形结构以表示“部分-整体”层次。 统一处理单个对象和组合对象。
class File {
constructor(name) { this.name = name; }
display() { console.log(this.name); }
}
class Folder {
constructor(name) {
this.name = name;
this.children = [];
}
add(item) { this.children.push(item); }
display() {
console.log(this.name);
this.children.forEach(c => c.display());
}
}
const root = new Folder('root');
root.add(new File('file1'));
const sub = new Folder('sub');
sub.add(new File('file2'));
root.add(sub);
root.display();
9. 装饰器模式(Decorator)
动态时在具体逻辑前植入新的逻辑,比继承更灵活。
function withTimestamp(fn) {
return function(...args) {
console.log('Timestamp:', Date.now());
return fn(...args);
};
}
const sayHello = withTimestamp(() => console.log('Hello'));
sayHello();
10. 外观模式(Facade)
为子系统提供统一的简化接口。把多个调用合并一个。
class CPU { start() { console.log('CPU Start'); } }
class Memory { load() { console.log('Memory Load'); } }
class Computer {
constructor() {
this.cpu = new CPU();
this.memory = new Memory();
}
boot() {
this.cpu.start();
this.memory.load();
}
}
const pc = new Computer();
pc.boot();
11. 享元模式(Flyweight)
通过缓存已经请求过的对象,提高下次访问速度。
const shapeFactory = (() => {
const shapes = {};
return {
getCircle: color => {
if (!shapes[color]) {
shapes[color] = { color };
}
return shapes[color];
}
};
})();
const red1 = shapeFactory.getCircle('red');
const red2 = shapeFactory.getCircle('red');
console.log(red1 === red2); // true
12. 代理模式(Proxy)
为其他对象提供一种代理以控制对这个对象的访问。
const user = {
name: 'John',
age: 30
};
const proxy = new Proxy(user, {
get(target, prop) {
console.log(`Getting ${prop}`);
return target[prop];
}
});
console.log(proxy.name);
三、行为型模式
关注对象之间的交互和职责分配。
13. 责任链模式(Chain of Responsibility)*
将请求的发送者和接收者解耦,使多个对象都有机会处理请求。 链式处理请求。
function handler1(req, next) {
if (req === 'ok') return 'Handled by 1';
return next(req);
}
function handler2(req) {
return 'Handled by 2';
}
function chain(req) {
return handler1(req, handler2);
}
console.log(chain('error'));
14. 命令模式(Command)
将请求封装为对象,使你可以用不同的请求参数化其他对象。 将请求封装为对象。
class Light {
on() { console.log('Light On'); }
off() { console.log('Light Off'); }
}
class Command {
constructor(light) { this.light = light; }
execute() { this.light.on(); }
}
const cmd = new Command(new Light());
cmd.execute();
15. 解释器模式(Interpreter)
给定一种语言,定义它的文法表示,并定义一个解释器来解释该语言。 定义语言的文法规则。
const context = { A: true, B: false };
function interpret(expr) {
return context[expr];
}
console.log(interpret('A')); // true
16. 迭代器模式(Iterator)
提供一种方法顺序访问聚合对象的元素,而不暴露其底层表示。 统一遍历方式。
const iterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let i = 0;
return {
next: () => ({ done: i >= this.data.length, value: this.data[i++] })
};
}
};
for (let val of iterable) console.log(val);
17. 中介者模式(Mediator)*
用一个中介对象封装一系列对象交互,使对象之间松耦合。 集中控制交互。
class Mediator {
send(message, sender) {
this.receiver.receive(message, sender);
}
}
class Colleague {
constructor(name, mediator) {
this.name = name;
this.mediator = mediator;
}
send(msg) {
this.mediator.send(msg, this.name);
}
receive(msg, sender) {
console.log(`${this.name} got "${msg}" from ${sender}`);
}
}
const mediator = new Mediator();
const c1 = new Colleague('A', mediator);
const c2 = new Colleague('B', mediator);
mediator.receiver = c2;
c1.send('Hello');
18. 备忘录模式(Memento)
在不破坏封装的前提下,捕获并外部化一个对象的内部状态以便恢复。 保存和恢复状态。
class Editor {
constructor() {
this.content = '';
this.history = [];
}
write(text) {
this.history.push(this.content);
this.content += text;
}
undo() {
this.content = this.history.pop();
}
}
const editor = new Editor();
editor.write('Hello ');
editor.write('World');
editor.undo();
console.log(editor.content); // Hello
19. 观察者模式(Observer)
定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都得到通知。 发布-订阅机制。
class Subject {
constructor() { this.observers = []; }
subscribe(fn) { this.observers.push(fn); }
notify(data) { this.observers.forEach(fn => fn(data)); }
}
const subject = new Subject();
subject.subscribe(data => console.log('Got:', data));
subject.notify('Hello');
20. 状态模式(State)*
允许对象在其内部状态改变时改变其行为。 状态驱动行为。
class Light {
constructor() {
this.state = new OffState();
}
toggle() {
this.state = this.state.toggle();
}
}
class OffState {
toggle() {
console.log('Turning On');
return new OnState();
}
}
class OnState {
toggle() {
console.log('Turning Off');
return new OffState();
}
}
const light = new Light();
light.toggle(); // Turning On
light.toggle(); // Turning Off
21. 策略模式(Strategy)
定义一系列算法,封装每个算法,并使它们可以互换。
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function calculate(a, b, strategy) {
return strategy(a, b);
}
console.log(calculate(3, 1, subtract)); // 2
console.log(calculate(3, 1, add));
22. 模板方法模式(Template Method)
定义一个操作中的算法骨架,将某些步骤延迟到子类中实现。 固定流程,可变步骤。主要继承实现
class Game {
start() {
this.init();
this.play();
this.end();
}
init() {}
play() {}
end() {}
}
class Chess extends Game {
init() { console.log('Chess Init'); }
play() { console.log('Chess Playing'); }
end() { console.log('Chess End'); }
}
new Chess().start();
23. 访问者模式(Visitor)*
表示一个作用于某对象结构中的各元素的操作,使你可以在不改变各元素的类的前提下定义新的操作。 分离数据结构和操作。
class Animal {
accept(visitor) {
visitor.visit(this);
}
}
class Visitor {
visit(animal) {
console.log('Visiting', animal.constructor.name);
}
}
const animal = new Animal();
animal.accept(new Visitor());