您现在的位置是:网站首页 > 设计模式实现文章详情
设计模式实现
陈川
【
JavaScript
】
57192人已围观
14753字
设计模式概述
设计模式是解决软件设计中常见问题的可重用方案。在JavaScript中,设计模式可以帮助开发者编写更清晰、更易维护的代码。这些模式分为创建型、结构型和行为型三大类,每种模式针对特定类型的问题提供解决方案。
单例模式
单例模式确保一个类只有一个实例,并提供全局访问点。这在需要共享资源或控制访问时特别有用。
class Singleton {
constructor() {
if (!Singleton.instance) {
Singleton.instance = this;
this.data = [];
}
return Singleton.instance;
}
addData(item) {
this.data.push(item);
}
getData() {
return this.data;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
instance1.addData('test');
console.log(instance2.getData()); // ['test']
console.log(instance1 === instance2); // true
工厂模式
工厂模式提供创建对象的接口,让子类决定实例化哪个类。这种模式将对象的创建与使用分离。
class Car {
constructor(options) {
this.type = options.type || 'sedan';
this.color = options.color || 'white';
}
}
class Truck {
constructor(options) {
this.type = options.type || 'truck';
this.color = options.color || 'blue';
}
}
class VehicleFactory {
createVehicle(options) {
switch(options.vehicleType) {
case 'car':
return new Car(options);
case 'truck':
return new Truck(options);
default:
throw new Error('Invalid vehicle type');
}
}
}
const factory = new VehicleFactory();
const myCar = factory.createVehicle({ vehicleType: 'car', color: 'red' });
const myTruck = factory.createVehicle({ vehicleType: 'truck' });
观察者模式
观察者模式定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知。
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
update(data) {
console.log(`Observer received data: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify('Hello World!');
// Output:
// Observer received data: Hello World!
// Observer received data: Hello World!
装饰器模式
装饰器模式动态地给对象添加额外职责,相比继承更加灵活。
class Coffee {
cost() {
return 5;
}
}
class MilkDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 2;
}
}
class SugarDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost() + 1;
}
}
let myCoffee = new Coffee();
myCoffee = new MilkDecorator(myCoffee);
myCoffee = new SugarDecorator(myCoffee);
console.log(myCoffee.cost()); // 8
策略模式
策略模式定义一系列算法,封装每个算法,并使它们可以互换。
class Shipping {
constructor(strategy) {
this.strategy = strategy;
}
calculate(package) {
return this.strategy.calculate(package);
}
}
class UPS {
calculate(package) {
return package.weight * 0.45;
}
}
class Fedex {
calculate(package) {
return package.weight * 0.65;
}
}
const package = { weight: 10 };
const ups = new Shipping(new UPS());
const fedex = new Shipping(new Fedex());
console.log(ups.calculate(package)); // 4.5
console.log(fedex.calculate(package)); // 6.5
适配器模式
适配器模式将一个类的接口转换成客户希望的另一个接口,使原本不兼容的类可以一起工作。
class OldCalculator {
operations(term1, term2, operation) {
switch(operation) {
case 'add':
return term1 + term2;
case 'sub':
return term1 - term2;
default:
return NaN;
}
}
}
class NewCalculator {
add(term1, term2) {
return term1 + term2;
}
sub(term1, term2) {
return term1 - term2;
}
}
class CalculatorAdapter {
constructor() {
this.calculator = new NewCalculator();
}
operations(term1, term2, operation) {
switch(operation) {
case 'add':
return this.calculator.add(term1, term2);
case 'sub':
return this.calculator.sub(term1, term2);
default:
return NaN;
}
}
}
const oldCalc = new OldCalculator();
console.log(oldCalc.operations(10, 5, 'add')); // 15
const newCalc = new NewCalculator();
console.log(newCalc.add(10, 5)); // 15
const adapter = new CalculatorAdapter();
console.log(adapter.operations(10, 5, 'add')); // 15
代理模式
代理模式为其他对象提供一种代理以控制对这个对象的访问。
class RealImage {
constructor(filename) {
this.filename = filename;
this.loadFromDisk();
}
display() {
console.log(`Displaying ${this.filename}`);
}
loadFromDisk() {
console.log(`Loading ${this.filename} from disk`);
}
}
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('test.jpg');
// 此时图片还未加载
image.display(); // 加载并显示图片
// 第二次调用不会重新加载
image.display();
状态模式
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
class TrafficLight {
constructor() {
this.states = [new GreenLight(), new YellowLight(), new RedLight()];
this.current = this.states[0];
}
change() {
const totalStates = this.states.length;
let currentIndex = this.states.indexOf(this.current);
this.current = this.states[(currentIndex + 1) % totalStates];
}
sign() {
return this.current.sign();
}
}
class LightState {
constructor(light) {
this.light = light;
}
sign() {
throw new Error('This method must be implemented');
}
}
class GreenLight extends LightState {
sign() {
return 'Green - Go';
}
}
class YellowLight extends LightState {
sign() {
return 'Yellow - Caution';
}
}
class RedLight extends LightState {
sign() {
return 'Red - Stop';
}
}
const trafficLight = new TrafficLight();
console.log(trafficLight.sign()); // Green - Go
trafficLight.change();
console.log(trafficLight.sign()); // Yellow - Caution
trafficLight.change();
console.log(trafficLight.sign()); // Red - Stop
trafficLight.change();
console.log(trafficLight.sign()); // Green - Go
命令模式
命令模式将请求封装为对象,从而允许使用不同的请求、队列或日志来参数化其他对象。
class Light {
turnOn() {
console.log('Light is on');
}
turnOff() {
console.log('Light is off');
}
}
class Switch {
constructor(onCommand, offCommand) {
this.onCommand = onCommand;
this.offCommand = offCommand;
}
on() {
this.onCommand.execute();
}
off() {
this.offCommand.execute();
}
}
class Command {
constructor(light) {
this.light = light;
}
execute() {
throw new Error('This method must be implemented');
}
}
class TurnOnCommand extends Command {
execute() {
this.light.turnOn();
}
}
class TurnOffCommand extends Command {
execute() {
this.light.turnOff();
}
}
const light = new Light();
const switchUp = new Switch(
new TurnOnCommand(light),
new TurnOffCommand(light)
);
switchUp.on(); // Light is on
switchUp.off(); // Light is off
组合模式
组合模式将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
class Component {
constructor(name) {
this.name = name;
}
add(component) {
throw new Error('This method must be implemented');
}
remove(component) {
throw new Error('This method must be implemented');
}
display(depth) {
throw new Error('This method must be implemented');
}
}
class Leaf extends Component {
constructor(name) {
super(name);
}
display(depth) {
console.log(`${'-'.repeat(depth)}${this.name}`);
}
}
class Composite extends Component {
constructor(name) {
super(name);
this.children = [];
}
add(component) {
this.children.push(component);
}
remove(component) {
const index = this.children.indexOf(component);
if (index !== -1) {
this.children.splice(index, 1);
}
}
display(depth) {
console.log(`${'-'.repeat(depth)}${this.name}`);
this.children.forEach(child => {
child.display(depth + 2);
});
}
}
const root = new Composite('root');
root.add(new Leaf('Leaf A'));
root.add(new Leaf('Leaf B'));
const comp = new Composite('Composite X');
comp.add(new Leaf('Leaf XA'));
comp.add(new Leaf('Leaf XB'));
root.add(comp);
root.add(new Leaf('Leaf C'));
root.display(0);
迭代器模式
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示。
class Iterator {
constructor(items) {
this.index = 0;
this.items = items;
}
first() {
this.reset();
return this.next();
}
next() {
return this.items[this.index++];
}
hasNext() {
return this.index <= this.items.length;
}
reset() {
this.index = 0;
}
each(callback) {
for (let item = this.first(); this.hasNext(); item = this.next()) {
callback(item);
}
}
}
const items = ['Apple', 'Banana', 'Cherry', 'Date'];
const iter = new Iterator(items);
iter.each(function(item) {
console.log(item);
});
模板方法模式
模板方法模式定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法结构的情况下,重新定义算法的某些特定步骤。
class DataExporter {
export() {
this.prepareData();
this.formatData();
this.sendData();
this.cleanUp();
}
prepareData() {
throw new Error('This method must be implemented');
}
formatData() {
console.log('Formatting data in default format');
}
sendData() {
console.log('Sending data to default destination');
}
cleanUp() {
console.log('Cleaning up temporary files');
}
}
class CSVExporter extends DataExporter {
prepareData() {
console.log('Preparing data for CSV export');
}
formatData() {
console.log('Formatting data as CSV');
}
}
class JSONExporter extends DataExporter {
prepareData() {
console.log('Preparing data for JSON export');
}
formatData() {
console.log('Formatting data as JSON');
}
sendData() {
console.log('Sending JSON data to API endpoint');
}
}
const csvExporter = new CSVExporter();
csvExporter.export();
const jsonExporter = new JSONExporter();
jsonExporter.export();
中介者模式
中介者模式用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
class ChatRoom {
showMessage(user, message) {
const time = new Date().toLocaleTimeString();
console.log(`${time} [${user.getName()}]: ${message}`);
}
}
class User {
constructor(name, chatMediator) {
this.name = name;
this.chatMediator = chatMediator;
}
getName() {
return this.name;
}
send(message) {
this.chatMediator.showMessage(this, message);
}
}
const mediator = new ChatRoom();
const john = new User('John Doe', mediator);
const jane = new User('Jane Doe', mediator);
john.send('Hi there!');
jane.send('Hey!');
备忘录模式
备忘录模式在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后恢复对象到原先保存的状态。
class EditorMemento {
constructor(content) {
this.content = content;
}
getContent() {
return this.content;
}
}
class Editor {
constructor() {
this.content = '';
}
type(words) {
this.content = this.content + ' ' + words;
}
getContent() {
return this.content.trim();
}
save() {
return new EditorMemento(this.content);
}
restore(memento) {
this.content = memento.getContent();
}
}
const editor = new Editor();
editor.type('This is the first sentence.');
editor.type('This is second.');
const saved = editor.save();
editor.type('And this is third.');
console.log(editor.getContent()); // This is the first sentence. This is second. And this is third.
editor.restore(saved);
console.log(editor.getContent()); // This is the first sentence. This is second.
访问者模式
访问者模式表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
class Employee {
constructor(name, salary) {
this.name = name;
this.salary = salary;
}
getSalary() {
return this.salary;
}
accept(visitor) {
visitor.visit(this);
}
}
class ExtraSalaryVisitor {
visit(employee) {
employee.salary = employee.getSalary() * 1.1;
}
}
class ExtraVacationVisitor {
visit(employee) {
employee.vacationDays = 10;
}
}
const employees = [
new Employee('John', 50000),
new Employee('Jane', 60000),
new Employee('Bob', 40000)
];
const salaryVisitor = new ExtraSalaryVisitor();
const vacationVisitor = new ExtraVacationVisitor();
employees.forEach(emp => {
emp.accept(salaryVisitor);
emp.accept(vacationVisitor);
console.log(`${emp.name}: $${emp.salary} and ${emp.vacationDays} vacation days`);
});
责任链模式
责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。
class Handler {
constructor() {
this.nextHandler = null;
}
setNext(handler) {
this.nextHandler = handler;
return handler;
}
handle(request) {
if (this.nextHandler) {
return this.nextHandler.handle(request);
}
return null;
}
}
class ConcreteHandler1 extends Handler {
handle(request) {
if (request === 'request1') {
return `Handler1: I'll handle the ${request}.`;
}
return super.handle(request);
}
}
class ConcreteHandler2 extends Handler {
handle(request) {
if (request === 'request2') {
return `Handler2: I'll handle the ${request}.`;
}
return super.handle(request);
}
}
class ConcreteHandler3 extends Handler {
handle(request) {
if (request === 'request3') {
return `Handler3: I'll handle the ${request}.`;
}
return super.handle(request);
}
}
const handler1 = new ConcreteHandler1();
const handler2 = new ConcreteHandler2();
const handler3 = new ConcreteHandler3();
handler1.setNext(handler2).setNext(handler3);
console.log(handler1.handle('request1')); // Handler1: I'll handle the request1.
console.log(handler1.handle('request2')); // Handler2: I'll handle the request2.
console.log(handler1.handle('request3')); // Handler3: I'll handle the request3.
console.log(handler1.handle('request4')); // null
享元模式
享元模式运用共享技术有效地支持大量细粒度的对象。
class Flyweight {
constructor(sharedState) {
this.sharedState = sharedState;
}
operation(uniqueState) {
const s = JSON.stringify(this.sharedState);
const u = JSON.stringify(uniqueState);
console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`);
}
}
class FlyweightFactory {
constructor() {
this.flyweights = {};
}
getFlyweight(sharedState) {
const key = JSON.stringify(sharedState);
if (!this.flyweights[key]) {
console.log(`FlyweightFactory: Can't find a flyweight, creating new one.`);
this.flyweights[key] = new Flyweight(sharedState);
} else {
console.log(`FlyweightFactory: Reusing existing flyweight.`);
}
return this.flyweights[key];