跳转到内容

设计模式

原型模式

作用: 公共方法存放在原型。 好处: 在原型添加新方法,现有实例即时生效; 内存节省。

js
// 定义敌人原型
function Enemy(type) {
	this.type = type;
}

// 共享攻击方法(所有敌人都会)
Enemy.prototype.attack = function () {
	console.log(`${this.type}发起攻击!`);
};

// 创建实例
const dragon = new Enemy('火龙');
const goblin = new Enemy('哥布林');

dragon.attack(); // 火龙发起攻击!
goblin.attack(); // 哥布林发起攻击!

// 验证方法共享
console.log(dragon.attack === goblin.attack);

工厂模式

作用: 根据不同的需求创建不同类型的对象,不需要去 new 直接获取实例

js
// 定义一个基类 Animal
class Animal {
	speak() {
		return this.makeSound();
	}
}

// 定义具体的 Dog 类
class Dog extends Animal {
	makeSound() {
		return 'Woof'; // 狗的叫声
	}
}

// 定义具体的 Cat 类
class Cat extends Animal {
	makeSound() {
		return 'Meow'; // 猫的叫声
	}
}

// 工厂类,负责创建不同类型的动物对象
class AnimalFactory {
	createAnimal(type) {
		switch (type) {
			case 'dog':
				return new Dog(); // 创建 Dog 实例
			case 'cat':
				return new Cat(); // 创建 Cat 实例
			default:
				throw new Error('Unknown animal type'); // 如果类型未知,抛出错误
		}
	}
}

// 使用工厂模式创建对象
const factory = new AnimalFactory();
const dog = factory.createAnimal('dog'); // 创建 Dog 实例
console.log(dog.speak()); // 输出:Woof
const cat = factory.createAnimal('cat'); // 创建 Cat 实例
console.log(cat.speak()); // 输出:Meow

单例模式

作用: 确保一个类只有一个实例,并提供一个全局访问点 实现: 如果存在实例则返回当前实例

js
// 定义一个 Logger 类
class Logger {
	constructor() {
		if (Logger.instance) {
			return Logger.instance; // 如果已经存在实例,直接返回
		}
		this.messages = []; // 用于存储日志消息
		Logger.instance = this; // 保存当前实例
	}

	log(message) {
		this.messages.push(message); // 添加日志消息
	}

	getLogs() {
		return this.messages; // 获取所有日志消息
	}
}

// 使用单例模式
const logger1 = new Logger();
logger1.log('Hello'); // 添加日志

const logger2 = new Logger();
logger2.log('World'); // 添加日志

console.log(logger1.getLogs()); // 输出:["Hello", "World"]
console.log(logger1 === logger2); // 输出:true(logger1 和 logger2 是同一个实例)

代理模式

作用: 通过创建一个代理对象来控制对实际对象的访问,代理对象可以添加额外的逻辑,比如权限检查、缓存、远程调用等

js
// 定义一个真实对象
class RealSubject {
	request() {
		return 'RealSubject: Handling request.'; // 真实对象的请求方法
	}
}

// 定义一个代理对象
class Proxy {
	constructor(realSubject) {
		this.realSubject = realSubject; // 保存真实对象的引用
	}

	request() {
		if (this.checkAccess()) {
			// 检查权限
			this.realSubject.request(); // 调用真实对象的请求方法
			this.logAccess(); // 记录日志
		}
	}

	checkAccess() {
		console.log('Proxy: Logging the time of request.'); // 记录请求时间
		return true; // 假设权限检查通过
	}

	logAccess() {
		console.log('Proxy: Logging the request.'); // 记录请求
	}
}

// 使用代理模式
const realSubject = new RealSubject(); // 创建真实对象
const proxy = new Proxy(realSubject); // 创建代理对象
proxy.request(); // 调用代理的请求方法

观察者模式

作用: 一对多的依赖关系,让多个观察者对象同时监听某一个主题对象;当主题对象发生变化时,所有依赖它的观察者都会自动收到通知并进行更新

js
class Subject {
	constructor(age) {
		this.observers = [];
		this._data = { name: '张三' };
		this._data.age = age; // 假设这是他们要订阅的数据
		console.log(this._data);
	}

	addObserver(observer) {
		this.observers.push(observer);
	}

	removeObserver(observer) {
		this.observers = this.observers.filter((item) => item !== observer);
	}

	notify() {
		this.observers.forEach((observer) => observer.update(this._data));
	}

	// 修改数据的方法
	setData(age) {
		this._data.age = age;
		this.notify(); // 数据变化后通知所有观察者
	}
}

// 观察者1
class ObserverA {
	update(data) {
		console.log('观察者A收到更新:', data.age);
	}
}

// 观察者2
class ObserverB {
	update(data) {
		console.log('观察者B收到更新:', `Hello, ${data.age}`);
	}
}

// 使用示例
const subject = new Subject(23);

const a = new ObserverA();
const b = new ObserverB();

subject.addObserver(a);
subject.addObserver(b);

// 更新数据
subject.setData(25);

策略模式

作用: 定义一系列算法,封装起来提供选择

js
// 定义一个上下文对象
class Context {
	constructor(strategy) {
		this.strategy = strategy; // 保存策略对象
	}

	executeStrategy(a, b) {
		return this.strategy(a, b); // 执行策略
	}
}

// 定义加法策略
function addStrategy(a, b) {
	return a + b; // 加法运算
}

// 定义减法策略
function subtractStrategy(a, b) {
	return a - b; // 减法运算
}

// 使用策略模式
const context = new Context(addStrategy); // 使用加法策略
console.log(context.executeStrategy(10, 5)); // 输出:15

context.strategy = subtractStrategy; // 切换到减法策略
console.log(context.executeStrategy(10, 5)); // 输出:5

装饰器模式

作用: 通过组合的方式,动态地扩展对象的功能

js
class Components {
	opertion() {
		return '这是组件基类';
	}
}

class CustomComponent extends Components {
	opertion() {
		return '这是自定义组件';
	}
}

// 在不修改自定义组件方法的前提下新增新功能
class Decorator extends Components {
	constructor(component) {
		super();
		this.component = component;
	}
	opertion() {
		// ...添加新功能
		console.log('装饰器添加的新功能...');
		return '这是装饰器' + this.component.opertion();
	}
}

const custom = new CustomComponent();
console.log(custom.opertion());

const decorator = new Decorator(custom);
console.log(decorator.opertion());

适配器模式

作用: 将一个类的接口转换成客户希望的另一个接口,使原本不兼容的接口能够兼容

js
// 具体播放器 - MP3(原生支持)
class Mp3Player {
	play(fileName) {
		console.log(`MP3 Player: 正在播放文件 - ${fileName}`);
	}
}

// 高级播放器 - VLC
class VlcPlayer {
	play(fileName) {
		console.log(`VLC Player: 正在播放 VLC 文件 - ${fileName}`);
	}
}

// 高级播放器 - MP4
class Mp4Player {
	play(fileName) {
		console.log(`MP4 Player: 正在播放 MP4 文件 - ${fileName}`);
	}
}

// 适配器统一接口
class MediaAdapter {
	// 点击播放,根据不同类型去找到不同的播放器
	static play(type, fileName) {
		const player = this._getPlayer(type); // 根据播放类型获取播放器实例
		if (player) {
			player.play(fileName);
		} else {
			console.log('不支持的音频格式' + type);
		}
	}

	// 私有方法:根据类型返回对应的播放器实例
	static _getPlayer(audioType) {
		switch (audioType.toLowerCase()) {
			case 'mp3':
				return new Mp3Player();
			case 'vlc':
				return new VlcPlayer();
			case 'mp4':
				return new Mp4Player();
			default:
				return null;
		}
	}
}

MediaAdapter.play('mp3', 'song.mp3'); //MP3 Player: 正在播放文件 - song.mp3
MediaAdapter.play('vlc', 'movie.vlc'); //VLC Player: 正在播放 VLC 文件 - movie.vlc
MediaAdapter.play('mp4', 'video.mp4'); //MP4 Player: 正在播放 MP4 文件 - video.mp4
MediaAdapter.play('avi', 'test.avi'); //不支持的音频格式avi

模板模式

作用: 它定义了一个算法的骨架,并允许子类在不改变算法结构的前提下重新定义算法中的某些步骤 固定一个某个行为的流程框架,但是又有一些不同的步骤,把这些步骤抽离出来去分别实现,保证整体流程顺序不变

js
class Beverage {
	// 固定模板方法
	templateMethod() {
		this.boilWater(); // 步骤1:烧水
		this.brew(); // 步骤2:冲泡(每种饮料都是不同的冲泡方式,由子类实现)
		this.pourInCup(); // 步骤3:倒进杯子里
		this.addCondiments(); // 步骤4:加调料(每种饮料都是不同的调料,由子类实现)
	}

	boilWater() {
		console.log('把水煮沸');
	}

	brew() {
		throw new Error('子类必须实现 brew 冲泡方法');
	}

	pourInCup() {
		console.log('倒入杯子');
	}

	addCondiments() {
		throw new Error('子类必须实现 addCondiments 加调料方法');
	}
}

class Coffee extends Beverage {
	brew() {
		console.log('用热水冲泡咖啡');
	}

	addCondiments() {
		console.log('加糖和牛奶');
	}
}

class Tea extends Beverage {
	brew() {
		console.log('用热水冲泡茶叶');
	}

	addCondiments() {
		console.log('加柠檬');
	}
}

// 制作饮料
class MakeBeverage {
	constructor(beverage) {
		this.beverage = beverage;
		this.beverage.templateMethod();
	}
}

console.log(' ********** 制作咖啡 ********** ');

const coffee = new MakeBeverage(new Coffee());
/*
    把水煮沸
    用热水冲泡咖啡
    倒入杯子
    加糖和牛奶
  */
console.log(' ********** 制作茶 ********** ');
const tea = new MakeBeverage(new Tea());
/*
    把水煮沸
    用热水冲泡茶叶
    倒入杯子
    加柠檬
  */

建造者模式

作用: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 把一个复杂的问题简单化分离出来,逐步去构建整体

js
// 定义一个复杂对象
class Car {
	constructor() {
		this.type = null; // 车型
		this.seats = null; // 座位数
		this.engine = null; // 发动机类型
		this.tripComputer = null; // 是否有行程计算机
		this.gps = null; // 是否有 GPS
	}
}

// 定义一个建造者类
class CarBuilder {
	constructor() {
		this.car = new Car(); // 创建一个 Car 实例
	}

	setType(type) {
		this.car.type = type; // 设置车型
		return this; // 返回当前对象,支持链式调用
	}

	setSeats(seats) {
		this.car.seats = seats; // 设置座位数
		return this; // 返回当前对象,支持链式调用
	}

	setEngine(engine) {
		this.car.engine = engine; // 设置发动机类型
		return this; // 返回当前对象,支持链式调用
	}

	setTripComputer(tripComputer) {
		this.car.tripComputer = tripComputer; // 设置行程计算机
		return this; // 返回当前对象,支持链式调用
	}

	setGPS(gps) {
		this.car.gps = gps; // 设置 GPS
		return this; // 返回当前对象,支持链式调用
	}

	build() {
		return this.car; // 返回构建好的 Car 实例
	}
}

// 使用建造者模式
const carBuilder = new CarBuilder(); // 创建建造者对象
const car = carBuilder
	.setType('SUV') // 设置车型为 SUV
	.setSeats(4) // 设置座位数为 4
	.setEngine('V6') // 设置发动机类型为 V6
	.setTripComputer(true) // 设置行程计算机为 true
	.setGPS(true) // 设置 GPS 为 true
	.build(); // 构建汽车

console.log(car); // 输出构建好的汽车对象

Will Try My Best.