设计模式是软件开发中解决常见问题的最佳实践方案。它们不仅能帮助我们写出更优雅、可维护的代码,还能提高代码的重用性和可扩展性。本文将介绍十个最常用的设计模式,并使用 TypeScript 来实现它们。
本文介绍的每个设计模式都包含以下内容:
建议读者:
单例模式确保一个类只有一个实例,并提供一个全局访问点。
// 数据库连接类
class DatabaseConnection {
private static instance: DatabaseConnection | null = null;
private connectionString: string;
private isConnected: boolean = false;
private constructor(connectionString: string) {
this.connectionString = connectionString;
}
public static getInstance(connectionString: string): DatabaseConnection {
if (!DatabaseConnection.instance) {
DatabaseConnection.instance = new DatabaseConnection(connectionString);
}
return DatabaseConnection.instance;
}
public connect(): void {
if (!this.isConnected) {
console.log(`连接到数据库: ${this.connectionString}`);
this.isConnected = true;
} else {
console.log('已经连接到数据库');
}
}
public disconnect(): void {
if (this.isConnected) {
console.log('断开数据库连接');
this.isConnected = false;
}
}
public query(sql: string): void {
if (this.isConnected) {
console.log(`执行查询: ${sql}`);
} else {
throw new Error('未连接到数据库');
}
}
}
// 使用示例
const db1 = DatabaseConnection.getInstance("mysql://localhost:3306/db1");
const db2 = DatabaseConnection.getInstance("mysql://localhost:3306/db1");
console.log('db1 === db2:', db1 === db2); // true
db1.connect();
// 输出: 连接到数据库: mysql://localhost:3306/db1
db2.connect();
// 输出: 已经连接到数据库
db1.query("SELECT * FROM users");
// 输出: 执行查询: SELECT * FROM users
db1.disconnect();
// 输出: 断开数据库连接
工厂模式提供了创建对象的接口,让子类决定实例化哪个类。
// 定义产品接口
interface Vehicle {
start(): void;
stop(): void;
getInfo(): string;
}
// 具体产品:汽车
class Car implements Vehicle {
private model: string;
private year: number;
constructor(model: string, year: number) {
this.model = model;
this.year = year;
}
start(): void {
console.log(`${this.model} 汽车启动`);
}
stop(): void {
console.log(`${this.model} 汽车停止`);
}
getInfo(): string {
return `${this.year}年 ${this.model} 汽车`;
}
}
// 具体产品:摩托车
class Motorcycle implements Vehicle {
private brand: string;
private type: string;
constructor(brand: string, type: string) {
this.brand = brand;
this.type = type;
}
start(): void {
console.log(`${this.brand} 摩托车启动`);
}
stop(): void {
console.log(`${this.brand} 摩托车停止`);
}
getInfo(): string {
return `${this.brand} ${this.type} 摩托车`;
}
}
// 工厂类
class VehicleFactory {
createCar(model: string, year: number): Vehicle {
return new Car(model, year);
}
createMotorcycle(brand: string, type: string): Vehicle {
return new Motorcycle(brand, type);
}
}
// 使用示例
const factory = new VehicleFactory();
// 创建汽车
const car = factory.createCar("Tesla Model 3", 2023);
console.log(car.getInfo()); // 输出: 2023年 Tesla Model 3 汽车
car.start(); // 输出: Tesla Model 3 汽车启动
// 创建摩托车
const motorcycle = factory.createMotorcycle("Harley-Davidson", "Street");
console.log(motorcycle.getInfo()); // 输出: Harley-Davidson Street 摩托车
motorcycle.start(); // 输出: Harley-Davidson 摩托车启动
策略模式定义了算法族,分别封装起来,让它们之间可以互相替换。
// 定义策略接口
interface PaymentStrategy {
pay(amount: number): void;
validate(): boolean;
}
// 具体策略:信用卡支付
class CreditCardPayment implements PaymentStrategy {
private cardNumber: string;
private expiryDate: string;
private cvv: string;
constructor(cardNumber: string, expiryDate: string, cvv: string) {
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
this.cvv = cvv;
}
validate(): boolean {
// 简化的验证逻辑
return this.cardNumber.length === 16 &&
this.cvv.length === 3;
}
pay(amount: number): void {
if (this.validate()) {
console.log(`使用信用卡支付 ${amount} 元`);
console.log(`卡号: ${this.maskCardNumber()}`);
} else {
throw new Error('信用卡信息无效');
}
}
private maskCardNumber(): string {
return '****' + this.cardNumber.slice(-4);
}
}
// 具体策略:支付宝支付
class AlipayPayment implements PaymentStrategy {
private email: string;
private password: string;
constructor(email: string, password: string) {
this.email = email;
this.password = password;
}
validate(): boolean {
// 简化的验证逻辑
return this.email.includes('@') &&
this.password.length >= 6;
}
pay(amount: number): void {
if (this.validate()) {
console.log(`使用支付宝支付 ${amount} 元`);
console.log(`账号: ${this.email}`);
} else {
throw new Error('支付宝账号信息无效');
}
}
}
// 支付处理器
class PaymentProcessor {
private strategy: PaymentStrategy;
constructor(strategy: PaymentStrategy) {
this.strategy = strategy;
}
setStrategy(strategy: PaymentStrategy): void {
this.strategy = strategy;
}
processPayment(amount: number): void {
this.strategy.pay(amount);
}
}
// 使用示例
// 创建支付策略
const creditCardPayment = new CreditCardPayment("1234567890123456", "12/24", "123");
const alipayPayment = new AlipayPayment("user@example.com", "password123");
// 创建支付处理器
const paymentProcessor = new PaymentProcessor(creditCardPayment);
// 使用信用卡支付
try {
paymentProcessor.processPayment(100);
// 输出:
// 使用信用卡支付 100 元
// 卡号: ****3456
} catch (error) {
console.error(error.message);
}
// 切换到支付宝支付
paymentProcessor.setStrategy(alipayPayment);
try {
paymentProcessor.processPayment(200);
// 输出:
// 使用支付宝支付 200 元
// 账号: user@example.com
} catch (error) {
console.error(error.message);
}
观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
// 定义观察者接口
interface Observer<T> {
update(data: T): void;
}
// 定义主题接口
interface Subject<T> {
attach(observer: Observer<T>): void;
detach(observer: Observer<T>): void;
notify(): void;
}
// 具体主题实现
class NewsAgency implements Subject<string> {
private observers: Set<Observer<string>> = new Set();
private news: string = '';
attach(observer: Observer<string>): void {
this.observers.add(observer);
}
detach(observer: Observer<string>): void {
this.observers.delete(observer);
}
notify(): void {
this.observers.forEach(observer => observer.update(this.news));
}
// 发布新闻
publishNews(news: string): void {
this.news = news;
this.notify();
}
}
// 具体观察者实现
class NewsSubscriber implements Observer<string> {
private name: string;
constructor(name: string) {
this.name = name;
}
update(news: string): void {
console.log(`${this.name} 收到新闻: ${news}`);
}
}
// 使用示例
const newsAgency = new NewsAgency();
const subscriber1 = new NewsSubscriber("订阅者1");
const subscriber2 = new NewsSubscriber("订阅者2");
newsAgency.attach(subscriber1);
newsAgency.attach(subscriber2);
newsAgency.publishNews("重大新闻:TypeScript 5.0 发布!");
// 输出:
// 订阅者1 收到新闻: 重大新闻:TypeScript 5.0 发布!
// 订阅者2 收到新闻: 重大新闻:TypeScript 5.0 发布!
newsAgency.detach(subscriber1);
newsAgency.publishNews("TypeScript 5.1 即将发布");
// 输出:
// 订阅者2 收到新闻: TypeScript 5.1 即将发布
装饰器模式动态地将责任附加到对象上,提供了比继承更有弹性的替代方案。
// 定义基础组件接口
interface Coffee {
cost(): number;
description(): string;
}
// 基础咖啡类
class SimpleCoffee implements Coffee {
cost(): number {
return 10;
}
description(): string {
return "简单咖啡";
}
}
// 抽象装饰器类
abstract class CoffeeDecorator implements Coffee {
protected coffee: Coffee;
constructor(coffee: Coffee) {
this.coffee = coffee;
}
cost(): number {
return this.coffee.cost();
}
description(): string {
return this.coffee.description();
}
}
// 具体装饰器:牛奶
class MilkDecorator extends CoffeeDecorator {
cost(): number {
return this.coffee.cost() + 2;
}
description(): string {
return this.coffee.description() + " + 牛奶";
}
}
// 具体装饰器:糖
class SugarDecorator extends CoffeeDecorator {
cost(): number {
return this.coffee.cost() + 1;
}
description(): string {
return this.coffee.description() + " + 糖";
}
}
// 具体装饰器:焦糖
class CaramelDecorator extends CoffeeDecorator {
cost(): number {
return this.coffee.cost() + 3;
}
description(): string {
return this.coffee.description() + " + 焦糖";
}
}
// 使用示例
const simpleCoffee = new SimpleCoffee();
console.log(simpleCoffee.description(), simpleCoffee.cost()); // 简单咖啡 10
let coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
coffee = new CaramelDecorator(coffee);
console.log(coffee.description(), coffee.cost());
// 输出: 简单咖啡 + 牛奶 + 糖 + 焦糖 16
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到中介的作用,并可以添加额外的功能。
// 定义接口
interface Image {
display(): void;
}
// 真实图片类
class RealImage implements Image {
private filename: string;
constructor(filename: string) {
this.filename = filename;
this.loadFromDisk();
}
private loadFromDisk(): void {
console.log(`加载图片: ${this.filename}`);
}
display(): void {
console.log(`显示图片: ${this.filename}`);
}
}
// 代理图片类
class ProxyImage implements Image {
private realImage: RealImage | null = null;
private filename: string;
private accessCount: number = 0;
constructor(filename: string) {
this.filename = filename;
}
display(): void {
// 懒加载
if (this.realImage === null) {
this.realImage = new RealImage(this.filename);
}
// 添加访问统计
this.accessCount++;
console.log(`图片被访问的次数: ${this.accessCount}`);
// 访问控制
if (this.accessCount <= 3) {
this.realImage.display();
} else {
console.log('访问次数超限,请升级会员');
}
}
}
// 使用示例
const image = new ProxyImage("test.jpg");
// 第一次访问,会加载图片
image.display();
// 输出:
// 加载图片: test.jpg
// 图片被访问的次数: 1
// 显示图片: test.jpg
// 第二次访问,使用缓存
image.display();
// 输出:
// 图片被访问的次数: 2
// 显示图片: test.jpg
// 第四次访问,超出限制
image.display();
image.display();
// 输出:
// 图片被访问的次数: 4
// 访问次数超限,请升级会员
适配器模式使接口不兼容的类可以一起工作,将一个类的接口转换成客户端期望的另一个接口。
// 目标接口(新接口)
interface ModernPayment {
processPayment(amount: number): void;
}
// 被适配的类(旧接口)
class LegacyPaymentSystem {
private name: string;
constructor(name: string) {
this.name = name;
}
makePayment(dollars: number): void {
console.log(`${this.name} 处理付款: ${dollars}美元`);
}
verifyAccount(accountId: string): boolean {
console.log(`验证账户: ${accountId}`);
return true;
}
}
// 支付适配器
class PaymentAdapter implements ModernPayment {
private legacySystem: LegacyPaymentSystem;
private accountId: string;
constructor(legacySystem: LegacyPaymentSystem, accountId: string) {
this.legacySystem = legacySystem;
this.accountId = accountId;
}
processPayment(amount: number): void {
// 添加账户验证逻辑
if (this.legacySystem.verifyAccount(this.accountId)) {
// 调用旧系统的支付方法
this.legacySystem.makePayment(amount);
} else {
throw new Error("账户验证失败");
}
}
}
// 现代支付处理器
class ModernPaymentProcessor {
private paymentSystem: ModernPayment;
constructor(paymentSystem: ModernPayment) {
this.paymentSystem = paymentSystem;
}
executePayment(amount: number): void {
console.log("使用现代支付处理器");
this.paymentSystem.processPayment(amount);
}
}
// 使用示例
const legacySystem = new LegacyPaymentSystem("旧支付系统");
const adapter = new PaymentAdapter(legacySystem, "user123");
const modernProcessor = new ModernPaymentProcessor(adapter);
// 使用现代接口处理支付
modernProcessor.executePayment(100);
// 输出:
// 使用现代支付处理器
// 验证账户: user123
// 旧支付系统 处理付款: 100美元
命令模式将请求封装成对象,使得可以用不同的请求参数化其他对象,并且支持请求的排队执行、记录日志、撤销等操作。
// 命令接口
interface Command {
execute(): void;
undo(): void;
}
// 接收者:文本编辑器
class TextEditor {
private content: string = '';
getContent(): string {
return this.content;
}
insertText(text: string): void {
this.content += text;
}
deleteText(length: number): void {
this.content = this.content.slice(0, -length);
}
}
// 具体命令:插入文本
class InsertCommand implements Command {
private editor: TextEditor;
private text: string;
constructor(editor: TextEditor, text: string) {
this.editor = editor;
this.text = text;
}
execute(): void {
this.editor.insertText(this.text);
}
undo(): void {
this.editor.deleteText(this.text.length);
}
}
// 具体命令:删除文本
class DeleteCommand implements Command {
private editor: TextEditor;
private deletedText: string = '';
private length: number;
constructor(editor: TextEditor, length: number) {
this.editor = editor;
this.length = length;
}
execute(): void {
const content = this.editor.getContent();
this.deletedText = content.slice(-this.length);
this.editor.deleteText(this.length);
}
undo(): void {
this.editor.insertText(this.deletedText);
}
}
// 命令调用者:编辑器操作历史
class EditorCommandHistory {
private commands: Command[] = [];
private undoneCommands: Command[] = [];
execute(command: Command): void {
command.execute();
this.commands.push(command);
this.undoneCommands = []; // 清空重做栈
}
undo(): void {
const command = this.commands.pop();
if (command) {
command.undo();
this.undoneCommands.push(command);
}
}
redo(): void {
const command = this.undoneCommands.pop();
if (command) {
command.execute();
this.commands.push(command);
}
}
}
// 使用示例
const editor = new TextEditor();
const history = new EditorCommandHistory();
// 执行插入命令
history.execute(new InsertCommand(editor, "Hello, "));
history.execute(new InsertCommand(editor, "World!"));
console.log(editor.getContent()); // 输出: Hello, World!
// 撤销最后一次操作
history.undo();
console.log(editor.getContent()); // 输出: Hello,
// 重做操作
history.redo();
console.log(editor.getContent()); // 输出: Hello, World!
// 删除操作
history.execute(new DeleteCommand(editor, 6));
console.log(editor.getContent()); // 输出: Hello,
// 撤销删除
history.undo();
console.log(editor.getContent()); // 输出: Hello, World!
责任链模式为请求创建了一个接收者对象的链。这种模式让多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
// 定义请求类型
interface Request {
type: 'LEAVE' | 'EXPENSE' | 'SALARY';
amount: number;
description: string;
}
// 抽象处理者
abstract class ApprovalHandler {
protected nextHandler: ApprovalHandler | null = null;
protected handlerName: string;
protected approvalLimit: number;
constructor(name: string, limit: number) {
this.handlerName = name;
this.approvalLimit = limit;
}
setNext(handler: ApprovalHandler): ApprovalHandler {
this.nextHandler = handler;
return handler;
}
handle(request: Request): void {
if (this.canHandle(request)) {
this.processRequest(request);
} else if (this.nextHandler) {
console.log(`${this.handlerName} 无法处理,转交给下一级`);
this.nextHandler.handle(request);
} else {
console.log('没有人能处理该请求');
}
}
protected abstract canHandle(request: Request): boolean;
protected abstract processRequest(request: Request): void;
}
// 具体处理者:主管
class Supervisor extends ApprovalHandler {
constructor() {
super('主管', 1000);
}
protected canHandle(request: Request): boolean {
return request.type === 'LEAVE' ||
(request.type === 'EXPENSE' && request.amount <= this.approvalLimit);
}
protected processRequest(request: Request): void {
console.log(`主管审批${request.type}: ${request.description}`);
}
}
// 具体处理者:经理
class Manager extends ApprovalHandler {
constructor() {
super('经理', 5000);
}
protected canHandle(request: Request): boolean {
return request.type === 'EXPENSE' && request.amount <= this.approvalLimit;
}
protected processRequest(request: Request): void {
console.log(`经理审批${request.type}: ${request.description}`);
}
}
// 具体处理者:总监
class Director extends ApprovalHandler {
constructor() {
super('总监', 10000);
}
protected canHandle(request: Request): boolean {
return request.type === 'EXPENSE' || request.type === 'SALARY';
}
protected processRequest(request: Request): void {
console.log(`总监审批${request.type}: ${request.description}`);
}
}
// 使用示例
const supervisor = new Supervisor();
const manager = new Manager();
const director = new Director();
// 设置责任链
supervisor.setNext(manager).setNext(director);
// 测试不同类型的请求
const requests: Request[] = [
{ type: 'LEAVE', amount: 0, description: '请假一天' },
{ type: 'EXPENSE', amount: 3000, description: '购买办公设备' },
{ type: 'EXPENSE', amount: 8000, description: '团建费用' },
{ type: 'SALARY', amount: 20000, description: '薪资调整' }
];
requests.forEach(request => {
console.log(`\n处理请求: ${request.description}`);
supervisor.handle(request);
});
// 输出示例:
// 处理请求: 请假一天
// 主管审批LEAVE: 请假一天
// 处理请求: 购买办公设备
// 主管无法处理,转交给下一级
// 经理审批EXPENSE: 购买办公设备
// 处理请求: 团建费用
// 主管无法处理,转交给下一级
// 经理无法处理,转交给下一级
// 总监审批EXPENSE: 团建费用
// 处理请求: 薪资调整
// 主管无法处理,转交给下一级
// 经理无法处理,转交给下一级
// 总监审批SALARY: 薪资调整
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
// 迭代器接口
interface Iterator<T> {
hasNext(): boolean;
next(): T;
current(): T;
reset(): void;
}
// 集合接口
interface Collection<T> {
createIterator(): Iterator<T>;
}
// 具体迭代器实现
class PlaylistIterator implements Iterator<Song> {
private playlist: Song[];
private position: number = 0;
constructor(playlist: Song[]) {
this.playlist = playlist;
this.position = 0;
}
hasNext(): boolean {
return this.position < this.playlist.length;
}
next(): Song {
if (this.hasNext()) {
const song = this.playlist[this.position];
this.position++;
return song;
}
throw new Error("没有更多歌曲了");
}
current(): Song {
if (this.position >= this.playlist.length) {
throw new Error("当前位置无效");
}
return this.playlist[this.position];
}
reset(): void {
this.position = 0;
}
}
// 歌曲类
class Song {
constructor(
public title: string,
public artist: string,
public duration: number
) {}
play(): void {
console.log(`正在播放: ${this.title} - ${this.artist} (${this.duration}秒)`);
}
}
// 具体集合:播放列表
class Playlist implements Collection<Song> {
private songs: Song[] = [];
addSong(song: Song): void {
this.songs.push(song);
}
removeSong(song: Song): void {
const index = this.songs.indexOf(song);
if (index !== -1) {
this.songs.splice(index, 1);
}
}
createIterator(): Iterator<Song> {
return new PlaylistIterator(this.songs);
}
}
// 音乐播放器
class MusicPlayer {
private playlist: Playlist;
private iterator: Iterator<Song>;
constructor(playlist: Playlist) {
this.playlist = playlist;
this.iterator = playlist.createIterator();
}
playAll(): void {
this.iterator.reset();
while (this.iterator.hasNext()) {
const song = this.iterator.next();
song.play();
}
}
playNext(): void {
if (this.iterator.hasNext()) {
const song = this.iterator.next();
song.play();
} else {
console.log("播放列表已结束");
}
}
}
// 使用示例
const playlist = new Playlist();
// 添加歌曲
playlist.addSong(new Song("Shape of You", "Ed Sheeran", 235));
playlist.addSong(new Song("Blinding Lights", "The Weeknd", 200));
playlist.addSong(new Song("Stay", "Justin Bieber", 138));
// 创建播放器
const player = new MusicPlayer(playlist);
// 播放所有歌曲
console.log("播放所有歌曲:");
player.playAll();
// 输出:
// 正在播放: Shape of You - Ed Sheeran (235秒)
// 正在播放: Blinding Lights - The Weeknd (200秒)
// 正在播放: Stay - Justin Bieber (138秒)
// 创建新的迭代器从头播放
const iterator = playlist.createIterator();
console.log("\n使用迭代器逐个播放:");
while (iterator.hasNext()) {
const song = iterator.next();
song.play();
}
单例模式:确保一个类只有一个实例 工厂模式:封装对象的创建过程 策略模式:封装可互换的行为 观察者模式:定义对象间的一对多依赖关系 装饰器模式:动态地给对象添加额外的职责 代理模式:为其他对象提供一个代理以控制对这个对象的访问 适配器模式:使不兼容的接口可以一起工作 命令模式:将请求封装成对象 责任链模式:处理请求的对象链 迭代器模式:顺序访问集合对象的元素