前端常用设计模式汇总
设计模式简介
根据设计模式的经典参考书《Design Patterns - Elements of Reusable Object-Oriented Software》(中文译名:设计模式 - 可复用的面向对象软件元素),设计模式主要分为三大类:创建型模式、结构型模式和行为型模式。本文将简述前端开发中常用的一些设计模式,帮助你在实际项目中应用这些模式,提升代码质量。
1. 设计模式的目的
设计模式旨在提高代码的封装性、可读性、重用性、可扩展性和可靠性,使项目更易于开发、维护和扩展。
2. 设计模式的分类
创建型模式:主要关注对象的创建方式。
- 工厂模式
- 单例模式
结构型模式:主要关注类和对象的组合。
- 外观模式
- 代理模式
行为型模式:主要关注对象之间的通信和协作。
- 策略模式
- 迭代器模式
- 观察者模式
- 中介者模式
- 访问者模式
3. 创建型模式
3.1 工厂模式
目的:定义一个创建对象的接口,可以方便地创建不同类型的对象,集中管理对象创建逻辑。
应用场景:需要根据不同条件创建不同实例时。
代码示例:
class ProductA {
constructor(name) {
this.name = name;
}
produce() {
console.log("produce A is producing..");
return `produce A: ${this.name}`;
}
}
class ProductB {
constructor(name) {
this.name = name;
}
produce() {
console.log("produce B is producing..");
return `product B: ${this.name}`;
}
}
class Factory {
create(type, name) {
switch (type) {
case "A":
return new ProductA(name);
case "B":
return new ProductB(name);
default:
throw new Error("不存在的产品类型");
}
}
}
// 使用
const factory = new Factory();
const productA = factory.create("A", "productA");
const productB = factory.create("B", "productB");
productA.produce(); // produce A is producing..
productB.produce(); // produce B is producing..
3.2 单例模式
目的:确保全局只有一个实例对象。
应用场景:需要全局唯一的对象,比如配置管理、日志记录等。
代码示例:
class Singleton {
constructor() {
if (typeof Singleton.instance === "object") {
return Singleton.instance;
}
this.name = "Singleton";
Singleton.instance = this;
return this;
}
}
const singleton1 = new Singleton();
const singleton2 = new Singleton();
console.log("对比:", singleton1 === singleton2); // true
4. 结构型模式
4.1 外观模式
目的:通过为多个复杂的子系统提供一个一致的接口,隐藏系统的复杂性。
应用场景:
- 为复杂的模块或子系统提供一个统一的访问接口。
- 子系统之间相对独立,外界不需要直接与子系统交互。
代码示例:
// 绑定事件
function addEvent(element, event, handler) {
if (element.addEventListener) {
element.addEventListener(event, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + event, handler);
} else {
element["on" + event] = fn;
}
}
// 取消绑定
function removeEvent(element, event, handler) {
if (element.removeEventListener) {
element.removeEventListener(event, handler, false);
} else if (element.detachEvent) {
element.detachEvent("on" + event, handler);
} else {
element["on" + event] = null;
}
}
4.2 代理模式
目的:通过一个代理对象控制对另一个对象的访问。
应用场景:
- 需要在访问某个对象时做一些额外操作,如延迟加载、缓存等。
- 直接访问某对象会导致一些不便或开销,可以通过代理模式优化访问。
代码示例:
class Image {
constructor(url) {
this.url = url;
this.loadImage();
}
loadImage() {
console.log(`Loading image from ${this.url}`);
}
}
class ProxyImage {
constructor(url) {
this.url = url;
}
loadImage() {
if (!this.image) {
this.image = new Image(this.url);
}
console.log(`Displaying cached image from ${this.url}`);
}
}
const proxyImage1 = new ProxyImage('https://example.com/image1.jpg');
proxyImage1.loadImage(); // Loading image from https://example.com/image1.jpg
proxyImage1.loadImage(); // Displaying cached image from https://example.com/image1.jpg
5. 行为型模式
5.1 策略模式
目的:定义一系列算法,将它们封装起来,并且使它们可以互相替换,优化代码中的 if-else
分支。
应用场景:需要在运行时选择不同的算法。
代码示例:
function Strategy(type, a, b) {
const Strategyer = {
add: function (a, b) {
return a + b;
},
subtract: function (a, b) {
return a - b;
},
multip: function (a, b) {
return a * b;
},
};
return Strategyer[type](a, b);
}
5.2 迭代器模式
目的:提供一种方法顺序访问一个聚合对象中各个元素, 而又无须暴露该对象的内部表示。
应用场景:需要对某个对象进行操作,但是又不能暴露内部细节。
代码示例:
const item = [1, 2, 3, 4, 5];
function Iterator(items) {
this.items = items;
this.index = 0;
}
Iterator.prototype = {
hasNext: function () {
return this.index < this.items.length;
},
next: function () {
return this.items[this.index++];
}
};
// 使用
const iterator = new Iterator(item);
while (iterator.hasNext()) {
console.log('迭代器:', iterator.next()); // 1, 2, 3, 4, 5
}
5.3 观察者模式
目的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
应用场景:需要在对象状态变化时通知多个依赖对象。
代码示例:
// 被观察者
function Subject() {
this.observers = [];
}
Subject.prototype = {
// 订阅
subscribe: function (observer) {
this.observers.push(observer);
},
// 取消订阅
unsubscribe: function (observerToRemove) {
this.observers = this.observers.filter(observer => observer !== observerToRemove);
},
// 事件触发
fire: function () {
this.observers.forEach(observer => observer.call());
}
};
// 使用
const subject = new Subject();
const observer1 = () => {
console.log('observer1 触发了...');
};
const observer2 = () => {
console.log('observer2 触发了...');
};
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.fire(); // observer1 触发了... observer2 触发了...
5.4 中介者模式
目的:通过一个中介对象来封装一系列对象之间的交互,从而减少对象之间的耦合。
应用场景:多个对象之间存在复杂的交互,使用中介者模式可以降低对象之间的耦合度。
代码示例:
// 聊天室成员类
class Member {
constructor(name) {
this.name = name;
this.chatroom = null;
}
// 发送消息
send(message, toMember) {
this.chatroom.send(message, this, toMember);
}
// 接收消息
receive(message, fromMember) {
console.log(`${fromMember.name} to ${this.name}: ${message}`);
}
}
// 聊天室类
class Chatroom {
constructor() {
this.members = {};
}
// 增加成员
addMember(member) {
this.members[member.name] = member;
member.chatroom = this;
}
// 发送消息
send(message, fromMember, toMember) {
toMember.receive(message, fromMember);
}
}
// 使用
const chatroom = new Chatroom();
const John = new Member('John');
const Tom = new
Member('Tom');
chatroom.addMember(John);
chatroom.addMember(Tom);
John.send('Hi Tom!', Tom); // John to Tom: Hi Tom!
5.5 访问者模式
目的:在不改变数据结构的前提下,增加新的操作。
应用场景:需要对一个对象结构中的对象进行不同的操作,而不影响这些对象的类。
代码示例:
// 财务报表类
class Report {
constructor(income, cost, profit) {
this.income = income;
this.cost = cost;
this.profit = profit;
}
}
// 老板类
class Boss {
get(data) {
console.log(`老板访问报表数据,盈利:${data}`);
}
}
// 财务人员类
class Account {
get(num1, num2) {
console.log(`财务人员访问报表数据,收入:${num1},支出: ${num2}`);
}
}
// 访问者类
function visitor(data, person) {
const handle = {
Boss: function (data) {
person.get(data.profit);
},
Account: function (data) {
person.get(data.income, data.cost);
}
};
handle[person.constructor.name](data);
}
// 使用
const report = new Report(1000, 500, 200);
visitor(report, new Account()); // 财务人员访问报表数据,收入:1000,支出: 500
visitor(report, new Boss()); // 老板访问报表数据,盈利:200
以上是一些常见的设计模式的介绍和应用示例。这些模式在开发中可以帮助解决常见问题,提升代码的结构和可维护性。了解并掌握这些设计模式,将有助于你在前端开发中写出更加优雅和高效的代码。