推荐答案
在 JavaScript 中,常用的设计模式包括但不限于以下几种:
- 单例模式(Singleton Pattern)
- 工厂模式(Factory Pattern)
- 观察者模式(Observer Pattern)
- 发布-订阅模式(Publish-Subscribe Pattern)
- 策略模式(Strategy Pattern)
- 代理模式(Proxy Pattern)
- 装饰器模式(Decorator Pattern)
- 适配器模式(Adapter Pattern)
- 模块模式(Module Pattern)
- 命令模式(Command Pattern)
本题详细解读
1. 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供一个全局访问点。在 JavaScript 中,可以通过闭包或模块模式实现单例。
// www.javascriptcn.com code example
const Singleton = (function() {
let instance;
function createInstance() {
const object = new Object("I am the instance");
return object;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true2. 工厂模式(Factory Pattern)
工厂模式提供了一种创建对象的方式,而无需指定具体的类。它通常用于创建复杂的对象。
// www.javascriptcn.com code example
function Car(options) {
this.doors = options.doors || 4;
this.color = options.color || "silver";
}
function Truck(options) {
this.doors = options.doors || 2;
this.color = options.color || "blue";
}
function VehicleFactory() {}
VehicleFactory.prototype.vehicleClass = Car;
VehicleFactory.prototype.createVehicle = function(options) {
if (options.vehicleType === "car") {
this.vehicleClass = Car;
} else {
this.vehicleClass = Truck;
}
return new this.vehicleClass(options);
};
const carFactory = new VehicleFactory();
const car = carFactory.createVehicle({ vehicleType: "car", color: "yellow", doors: 6 });
console.log(car instanceof Car); // true3. 观察者模式(Observer Pattern)
观察者模式定义对象间的一对多依赖关系,当一个对象改变状态时,所有依赖它的对象都会收到通知并自动更新。
// www.javascriptcn.com code example
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 {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer("Observer 1");
const observer2 = new Observer("Observer 2");
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify("Hello World!");
// Observer 1 received data: Hello World!
// Observer 2 received data: Hello World!4. 发布-订阅模式(Publish-Subscribe Pattern)
发布-订阅模式是观察者模式的一种变体,它使用一个中介(通常称为事件总线)来管理事件的发布和订阅。
// www.javascriptcn.com code example
class EventBus {
constructor() {
this.events = {};
}
subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
publish(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
}
const eventBus = new EventBus();
eventBus.subscribe("event1", data => {
console.log(`Event 1 received: ${data}`);
});
eventBus.publish("event1", "Hello Event Bus!");
// Event 1 received: Hello Event Bus!5. 策略模式(Strategy Pattern)
策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。策略模式让算法的变化独立于使用算法的客户。
// www.javascriptcn.com code example
const strategies = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
divide: (a, b) => a / b
};
function calculate(strategy, a, b) {
return strategies[strategy](a, b);
}
console.log(calculate("add", 10, 5)); // 15
console.log(calculate("subtract", 10, 5)); // 56. 代理模式(Proxy Pattern)
代理模式为其他对象提供一个代理或占位符,以控制对这个对象的访问。
// www.javascriptcn.com code example
class RealImage {
constructor(filename) {
this.filename = filename;
this.loadFromDisk();
}
loadFromDisk() {
console.log(`Loading ${this.filename}`);
}
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("test.jpg");
image.display(); // Loading test.jpg, Displaying test.jpg7. 装饰器模式(Decorator Pattern)
装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。
// www.javascriptcn.com code example
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 coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(coffee.cost()); // 88. 适配器模式(Adapter Pattern)
适配器模式将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
// www.javascriptcn.com code example
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.newCalculator = new NewCalculator();
}
operations(term1, term2, operation) {
switch (operation) {
case 'add':
return this.newCalculator.add(term1, term2);
case 'sub':
return this.newCalculator.sub(term1, term2);
default:
return NaN;
}
}
}
const oldCalculator = new OldCalculator();
console.log(oldCalculator.operations(10, 5, 'add')); // 15
const adapter = new CalculatorAdapter();
console.log(adapter.operations(10, 5, 'add')); // 159. 模块模式(Module Pattern)
模块模式用于创建私有和公共封装的方法和变量,防止污染全局命名空间。
// www.javascriptcn.com code example
const Module = (function() {
const privateVariable = "I am private";
function privateMethod() {
console.log(privateVariable);
}
return {
publicMethod: function() {
privateMethod();
}
};
})();
Module.publicMethod(); // I am private10. 命令模式(Command Pattern)
命令模式将请求封装为对象,从而使你可以用不同的请求对客户进行参数化。
// www.javascriptcn.com code example
class Command {
constructor(receiver) {
this.receiver = receiver;
}
execute() {
this.receiver.performAction();
}
}
class Receiver {
performAction() {
console.log("Action performed");
}
}
class Invoker {
constructor(command) {
this.command = command;
}
executeCommand() {
this.command.execute();
}
}
const receiver = new Receiver();
const command = new Command(receiver);
const invoker = new Invoker(command);
invoker.executeCommand(); // Action performed