JavaScript设计模式
什么是设计模式
设计模式是解决软件设计中常见问题的可复用解决方案。它们是经过验证的最佳实践,可以帮助开发者:
- 提高代码的可维护性和可复用性
- 使代码更具可读性和可理解性
- 促进团队成员之间的有效沟通
- 减少重复工作,提高开发效率
JavaScript中常用的设计模式
1. 单例模式(Singleton Pattern)
单例模式确保一个类只有一个实例,并提供全局访问点。
javascript
// 单例模式的实现
const Singleton = (function() {
let instance;
function createInstance() {
const object = new Object({ name: 'Singleton' });
return object;
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 使用单例模式
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
2. 工厂模式(Factory Pattern)
工厂模式提供一个创建对象的接口,让子类决定实例化哪一个类。
javascript
// 工厂模式的实现
function AnimalFactory() {
this.createAnimal = function(type) {
let animal;
if (type === 'dog') {
animal = new Dog();
} else if (type === 'cat') {
animal = new Cat();
} else if (type === 'bird') {
animal = new Bird();
}
animal.speak = function() {
return `${this.name} says ${this.sound}!`;
};
return animal;
};
}
function Dog() {
this.name = 'Dog';
this.sound = 'Woof';
}
function Cat() {
this.name = 'Cat';
this.sound = 'Meow';
}
function Bird() {
this.name = 'Bird';
this.sound = 'Tweet';
}
// 使用工厂模式
const factory = new AnimalFactory();
const dog = factory.createAnimal('dog');
const cat = factory.createAnimal('cat');
console.log(dog.speak()); // Dog says Woof!
console.log(cat.speak()); // Cat says Meow!
3. 观察者模式(Observer Pattern)
观察者模式定义了对象之间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知并更新。
javascript
// 观察者模式的实现
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!
subject.unsubscribe(observer1);
subject.notify('Goodbye!');
// Observer 2 received data: Goodbye!
4. 装饰器模式(Decorator Pattern)
装饰器模式允许向一个现有对象添加新的功能,同时不改变其结构。
javascript
// 装饰器模式的实现
class Coffee {
cost() {
return 5;
}
description() {
return 'Basic 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();
console.log(`${coffee.description()} costs ${coffee.cost()}`); // Basic Coffee costs $5
coffee = new MilkDecorator(coffee);
console.log(`${coffee.description()} costs ${coffee.cost()}`); // Basic Coffee, Milk costs $7
coffee = new SugarDecorator(coffee);
console.log(`${coffee.description()} costs ${coffee.cost()}`); // Basic Coffee, Milk, Sugar costs $8
5. 策略模式(Strategy Pattern)
策略模式定义了一系列算法,把它们一个个封装起来,并使它们可以互相替换。
javascript
// 策略模式的实现
class ShoppingCart {
constructor(discountStrategy) {
this.discountStrategy = discountStrategy;
this.items = [];
}
addItem(item) {
this.items.push(item);
}
calculateTotal() {
const subtotal = this.items.reduce((total, item) => total + item.price, 0);
return this.discountStrategy.calculateDiscount(subtotal);
}
setDiscountStrategy(strategy) {
this.discountStrategy = strategy;
}
}
class NoDiscount {
calculateDiscount(subtotal) {
return subtotal;
}
}
class PercentageDiscount {
constructor(percentage) {
this.percentage = percentage;
}
calculateDiscount(subtotal) {
return subtotal - (subtotal * this.percentage / 100);
}
}
class FixedDiscount {
constructor(amount) {
this.amount = amount;
}
calculateDiscount(subtotal) {
return subtotal - Math.min(this.amount, subtotal);
}
}
// 使用策略模式
const cart = new ShoppingCart(new NoDiscount());
cart.addItem({ name: 'Item 1', price: 100 });
cart.addItem({ name: 'Item 2', price: 200 });
console.log(`Total without discount: ${cart.calculateTotal()}`); // Total without discount: $300
cart.setDiscountStrategy(new PercentageDiscount(10));
console.log(`Total with 10% discount: ${cart.calculateTotal()}`); // Total with 10% discount: $270
cart.setDiscountStrategy(new FixedDiscount(50));
console.log(`Total with $50 discount: ${cart.calculateTotal()}`); // Total with $50 discount: $250
6. 代理模式(Proxy Pattern)
代理模式为其他对象提供一种代理以控制对这个对象的访问。
javascript
// 代理模式的实现
class RealImage {
constructor(filename) {
this.filename = filename;
this.loadFromDisk();
}
loadFromDisk() {
console.log(`Loading image: ${this.filename}`);
}
display() {
console.log(`Displaying image: ${this.filename}`);
}
}
class ImageProxy {
constructor(filename) {
this.filename = filename;
this.realImage = null;
}
display() {
if (this.realImage === null) {
this.realImage = new RealImage(this.filename);
}
this.realImage.display();
}
}
// 使用代理模式
const image = new ImageProxy('test.jpg');
// 图像不会被加载,直到调用display()
console.log('Image proxy created');
// 现在图像会被加载并显示
image.display();
// 图像已经加载过,只会显示
image.display();
7. 模块模式(Module Pattern)
模块模式用于创建具有私有和公共成员的模块。
javascript
// 模块模式的实现
const Calculator = (function() {
// 私有成员
let result = 0;
function validateNumber(num) {
return typeof num === 'number' && !isNaN(num);
}
// 公共成员
return {
add: function(a, b) {
if (validateNumber(a) && validateNumber(b)) {
result = a + b;
return result;
}
return 'Invalid numbers';
},
subtract: function(a, b) {
if (validateNumber(a) && validateNumber(b)) {
result = a - b;
return result;
}
return 'Invalid numbers';
},
multiply: function(a, b) {
if (validateNumber(a) && validateNumber(b)) {
result = a * b;
return result;
}
return 'Invalid numbers';
},
divide: function(a, b) {
if (validateNumber(a) && validateNumber(b)) {
if (b === 0) {
return 'Cannot divide by zero';
}
result = a / b;
return result;
}
return 'Invalid numbers';
},
getResult: function() {
return result;
}
};
})();
// 使用模块模式
console.log(Calculator.add(5, 3)); // 8
console.log(Calculator.subtract(5, 3)); // 2
console.log(Calculator.multiply(5, 3)); // 15
console.log(Calculator.divide(6, 3)); // 2
console.log(Calculator.getResult()); // 2
8. 迭代器模式(Iterator Pattern)
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部表示。
javascript
// 迭代器模式的实现
class Iterator {
constructor(collection) {
this.collection = collection;
this.index = 0;
}
next() {
return this.collection[this.index++];
}
hasNext() {
return this.index < this.collection.length;
}
}
class NumberCollection {
constructor(numbers) {
this.numbers = numbers;
}
createIterator() {
return new Iterator(this.numbers);
}
}
// 使用迭代器模式
const numbers = new NumberCollection([1, 2, 3, 4, 5]);
const iterator = numbers.createIterator();
while (iterator.hasNext()) {
console.log(iterator.next()); // 1, 2, 3, 4, 5
}
设计模式最佳实践
- 理解问题:在应用设计模式之前,确保你充分理解了问题
- 选择合适的模式:根据问题选择最适合的设计模式
- 不要过度使用:设计模式不是银弹,不要为了使用模式而使用模式
- 遵循原则:设计模式应该遵循SOLID原则
- 保持简单:尽量使用简单的解决方案,只有在必要时才使用复杂的设计模式
总结
设计模式是软件开发中的重要概念,它们提供了经过验证的解决方案来解决常见的设计问题。在JavaScript中,我们可以使用各种设计模式来提高代码的可维护性、可复用性和可读性。
选择合适的设计模式取决于具体的问题和需求。在实际开发中,应该根据项目的规模、复杂度和团队的熟悉程度来选择合适的设计模式。