设计模式
单例模式
一个类只有一个实例
发布-订阅模式
// Node中的EventEmitter 就是用的发布订阅模式
class EventEmitter {
constructor() {
this.list = {}
}
on(name, fn, type = 1) {
if (!this.list[name]) {
this.list[name] = []
}
this.list[name].push([fn, type])
}
once(name, fn, type = 0) {
this.on(name, fn, type)
}
emit(name, ...args) {
let fns = this.list[name]
if (!fns || fns.length === 0) return
fns.forEach((fn, index) => {
fn[0].apply(this, args)
if (fn[1] === 0) {
fns.splice(index, 1)
}
})
}
remove(name, func) {
let fns = this.list[name]
if (!fns) {
this.list[name] = []
}
fns.forEach((fn, index) => {
if (fn[0] === func) {
fns.splice(index, 1)
}
})
}
}
let bus = new EventEmitter()
bus.on("click", (value) => {
console.log(value)
})
bus.emit("click", 111)
观察者模式
class Publisher {
constructor() {
this.list = []
}
addListener(listener) {
this.list.push(listener)
}
removeListener(listener) {
this.list.forEach((item, index) => {
if (listener === item) {
this.list.splice(index, 1)
}
})
}
notify(obj) {
this.list.forEach((item) => {
item.process(obj)
})
}
}
class Subscriber {
process(obj) {
console.log(obj.name)
}
}
MVC
MVC (Model-View-Controller) 分为三部分
- Model(数据模型):数据
- View(视图):用户界面
- Controller(控制器):业务逻辑
通信过程如下,所有通信都是单向的。
- View 传送指令到 Controller
- Controller 完成业务逻辑后,要求 Model 改变状态
- Model 将新的数据发送到 View,用户得到反馈
MVVM
MVVM(Model-View-ViewModel)也分为三部分,数据模型,视图,视图模型。
与MVC的区别之一在于View和Model之间要借助ViewModel进行通信。
工厂模式
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。
// 简单工厂模式
class CarFactory {
static createCar(type) {
switch (type) {
case 'BMW':
return new BMW();
case 'Audi':
return new Audi();
case 'Mercedes':
return new Mercedes();
default:
throw new Error('Unknown car type');
}
}
}
class BMW {
constructor() {
this.brand = 'BMW';
this.type = 'Luxury';
}
}
class Audi {
constructor() {
this.brand = 'Audi';
this.type = 'Luxury';
}
}
// 使用
const bmw = CarFactory.createCar('BMW');
const audi = CarFactory.createCar('Audi');
装饰器模式
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。
class Coffee {
cost() {
return 5;
}
description() {
return 'Simple coffee';
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
description() {
return this.coffee.description() + ', milk';
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
description() {
return this.coffee.description() + ', sugar';
}
}
// 使用
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(coffee.description()); // Simple coffee, milk, sugar
console.log(coffee.cost()); // 8
策略模式
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。
// 策略类
class DiscountStrategy {
calculate(amount) {
throw new Error('calculate method must be implemented');
}
}
class RegularCustomer extends DiscountStrategy {
calculate(amount) {
return amount;
}
}
class PremiumCustomer extends DiscountStrategy {
calculate(amount) {
return amount * 0.9; // 10% 折扣
}
}
class VIPCustomer extends DiscountStrategy {
calculate(amount) {
return amount * 0.8; // 20% 折扣
}
}
// 上下文类
class ShoppingCart {
constructor(discountStrategy) {
this.discountStrategy = discountStrategy;
this.amount = 0;
}
setDiscountStrategy(discountStrategy) {
this.discountStrategy = discountStrategy;
}
addItem(price) {
this.amount += price;
}
calculateTotal() {
return this.discountStrategy.calculate(this.amount);
}
}
// 使用
const cart = new ShoppingCart(new RegularCustomer());
cart.addItem(100);
cart.addItem(50);
console.log(cart.calculateTotal()); // 150
cart.setDiscountStrategy(new VIPCustomer());
console.log(cart.calculateTotal()); // 120
适配器模式
适配器模式允许接口不兼容的类可以一起工作。
// 旧的接口
class OldPrinter {
oldPrint(text) {
console.log(`Old printer: ${text}`);
}
}
// 新的接口
class NewPrinter {
print(text) {
console.log(`New printer: ${text}`);
}
}
// 适配器
class PrinterAdapter {
constructor(oldPrinter) {
this.oldPrinter = oldPrinter;
}
print(text) {
this.oldPrinter.oldPrint(text);
}
}
// 使用
const oldPrinter = new OldPrinter();
const adapter = new PrinterAdapter(oldPrinter);
adapter.print('Hello World'); // Old printer: Hello World
代理模式
代理模式为其他对象提供一种代理以控制对这个对象的访问。
class RealImage {
constructor(filename) {
this.filename = filename;
this.loadFromDisk();
}
loadFromDisk() {
console.log(`Loading ${this.filename} from disk...`);
}
display() {
console.log(`Displaying ${this.filename}`);
}
}
class ProxyImage {
constructor(filename) {
this.filename = filename;
this.realImage = null;
}
display() {
if (!this.realImage) {
this.realImage = new RealImage(this.filename);
}
this.realImage.display();
}
}
// 使用
const image = new ProxyImage('photo.jpg');
// 图片只有在需要显示时才会被加载
image.display(); // Loading photo.jpg from disk... Displaying photo.jpg
image.display(); // Displaying photo.jpg (不会重新加载)
命令模式
命令模式将请求封装成对象,从而使您可以用不同的请求对客户进行参数化。
// 接收者
class Light {
turnOn() {
console.log('Light is ON');
}
turnOff() {
console.log('Light is OFF');
}
}
// 命令接口
class Command {
execute() {
throw new Error('execute method must be implemented');
}
undo() {
throw new Error('undo method must be implemented');
}
}
// 具体命令
class TurnOnCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOn();
}
undo() {
this.light.turnOff();
}
}
class TurnOffCommand extends Command {
constructor(light) {
super();
this.light = light;
}
execute() {
this.light.turnOff();
}
undo() {
this.light.turnOn();
}
}
// 调用者
class RemoteControl {
constructor() {
this.command = null;
this.history = [];
}
setCommand(command) {
this.command = command;
}
pressButton() {
if (this.command) {
this.command.execute();
this.history.push(this.command);
}
}
pressUndo() {
if (this.history.length > 0) {
const lastCommand = this.history.pop();
lastCommand.undo();
}
}
}
// 使用
const light = new Light();
const turnOnCommand = new TurnOnCommand(light);
const turnOffCommand = new TurnOffCommand(light);
const remote = new RemoteControl();
remote.setCommand(turnOnCommand);
remote.pressButton(); // Light is ON
remote.pressUndo(); // Light is OFF
remote.setCommand(turnOffCommand);
remote.pressButton(); // Light is OFF
remote.pressUndo(); // Light is ON