前端常見的8種設(shè)計模式,前端學(xué)習(xí)者的福音??!
在前端開發(fā)中,設(shè)計模式是一種被廣泛應(yīng)用的思想。設(shè)計模式可以幫助開發(fā)者解決常見的問題,并提供可重用的解決方案。本文將會介紹前端常見的設(shè)計模式,并通過代碼詳解它們的實現(xiàn)。

一、單例模式
單例模式是指一個類只能被實例化一次,并提供全局訪問點。這個模式非常適合那些需要共享資源的場景。比如,在前端開發(fā)中,我們經(jīng)常需要確保某些資源只被加載一次,而不是每次都重新加載。下面是一個使用單例模式的例子:
class Singleton {
?constructor() {
? ?if (typeof Singleton.instance === 'object') {
? ? ?return Singleton.instance;
? ?}
? ?this.name = 'Singleton';
? ?Singleton.instance = this;
? ?return this;
?}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // true
上述代碼中,我們創(chuàng)建了一個 Singleton 類,該類只能被實例化一次。如果多次嘗試實例化該類,將會返回同一個實例。這樣就保證了某些資源只會被加載一次,從而提高性能。
二、觀察者模式
觀察者模式是指當(dāng)一個對象狀態(tài)改變時,它的所有依賴者都會收到通知并自動更新。這個模式非常適合那些需要實時更新用戶界面的場景。下面是一個使用觀察者模式的例子:
class ObserverList {
?constructor() {
? ?this.observerList = [];
?}
?add(observer) {
? ?return this.observerList.push(observer);
?}
?remove(observer) {
? ?this.observerList = this.observerList.filter((obs) => obs !== observer);
?}
?count() {
? ?return this.observerList.length;
?}
?get(i) {
? ?return this.observerList[i];
?}
}
class Subject {
?constructor() {
? ?this.observers = new ObserverList();
?}
?addObserver(observer) {
? ?this.observers.add(observer);
?}
?removeObserver(observer) {
? ?this.observers.remove(observer);
?}
?notify(context) {
? ?const observerCount = this.observers.count();
? ?for (let i = 0; i < observerCount; i++) {
? ? ?this.observers.get(i).update(context);
? ?}
?}
}
class Observer {
?constructor() {
? ?this.update = () => {};
?}
}
const subject = new Subject();
const observer1 = new Observer();
observer1.update = function (context) {
?console.log(`Observer 1: ${context}`);
};
const observer2 = new Observer();
observer2.update = function (context) {
?console.log(`Observer 2: ${context}`);
};
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notify('Hello World');
上述代碼中,我們創(chuàng)建了一個 Subject 類和一個 Observer 類。Subject 類包含了一個觀察者列表,并提供了添加、刪除和通知觀察者的方法。Observer 類則包含了一個更新方法,用于處理來自被觀察者的通知。在主程序中,我們創(chuàng)建了兩個觀察者,并將它們添加到被觀察者的觀察者列表中。然后,我們通知被觀察者,被觀察者會自動通知所有觀察者,并執(zhí)行它們的更新方法。
三、工廠模式
工廠模式是指通過一個工廠類來創(chuàng)建其他類的實例。這個模式非常適合那些需要根據(jù)不同條件創(chuàng)建不同實例的場景。下面是一個使用工廠模式的例子:
class ProductA {
constructor(name) {
this.name = name;
}
operation() {
console.log(`Product A (${this.name}) is working.`);
}
}
class ProductB {
constructor(name) {
this.name = name;
}
operation() {
console.log(`Product B (${this.name}) is working.`);
}
}
class Factory {
createProduct(type, name) {
switch (type) {
case 'A':
return new ProductA(name);
case 'B':
return new ProductB(name);
default:
throw new Error('Invalid product type.');
}
}
}
const factory = new Factory();
const productA1 = factory.createProduct('A', 'productA1');
const productA2 = factory.createProduct('A', 'productA2');
const productB1 = factory.createProduct('B', 'productB1');
const productB2 = factory.createProduct('B', 'productB2');
productA1.operation(); // Product A (productA1) is working.
productA2.operation(); // Product A (productA2) is working.
productB1.operation(); // Product B (productB1) is working.
productB2.operation(); // Product B (productB2) is working.
上述代碼中,我們創(chuàng)建了兩個產(chǎn)品類 `ProductA` 和 `ProductB`,以及一個工廠類 `Factory`。工廠類提供了一個創(chuàng)建產(chǎn)品實例的方法 `createProduct`,該方法根據(jù)傳入的參數(shù)來決定創(chuàng)建哪種產(chǎn)品實例。在主程序中,我們通過工廠類創(chuàng)建了四個不同的產(chǎn)品實例,并分別執(zhí)行它們的操作方法。
四、裝飾者模式
裝飾者模式是指動態(tài)地給一個對象增加一些額外的功能。這個模式非常適合那些需要在運行時動態(tài)改變對象行為的場景。下面是一個使用裝飾者模式的例子:
class Shape {
draw() {}
}
class Circle extends Shape {
draw() {
console.log('Drawing a circle.');
}
}
class Rectangle extends Shape {
draw() {
console.log('Drawing a rectangle.');
}
}
class Decorator {
constructor(shape) {
this.shape = shape;
}
draw() {
this.shape.draw();
}
}
class RedShapeDecorator extends Decorator {
draw() {
this.shape.draw();
this.setRedBorder();
}
setRedBorder() {
console.log('Setting red border.');
}
}
const circle = new Circle();
const rectangle = new Rectangle();
circle.draw(); // Drawing a circle.
rectangle.draw(); // Drawing a rectangle.
const redCircle = new RedShapeDecorator(new Circle());
const redRectangle = new RedShapeDecorator(new Rectangle());
redCircle.draw(); // Drawing a circle. Setting red border.
redRectangle.draw(); // Drawing a rectangle. Setting red border.
上述代碼中,我們創(chuàng)建了兩個形狀類 Circle 和 Rectangle,以及一個裝飾者類 Decorator。裝飾者類包含了一個形狀對象,用于對其進行裝飾。然后,我們創(chuàng)建了一個紅色形狀裝飾者類 RedShapeDecorator,用于在形狀周圍添加一個紅色邊框。在主程序中,我們先執(zhí)行原始形狀的繪制方法,然后再使用紅色裝飾器對其進行裝飾。
五、代理模式
代理模式是指使用一個代理對象來控制對另一個對象的訪問。這個模式非常適合那些需要控制對某些敏感資源的訪問的場景。下面是一個使用代理模式的例子:
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 image1 = new Image('https://example.com/image1.jpg');
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
const image2 = new Image('https://example.com/image2.jpg');
const proxyImage2 = new ProxyImage('https://example.com/image2.jpg');
proxyImage2.loadImage(); // Loading image from https://example.com/image2.jpg
proxyImage2.loadImage(); // Displaying cached image from https://example.com/image2.jpg
上述代碼中,我們創(chuàng)建了一個圖片類 `Image` 和一個代理圖片類 `ProxyImage`。代理圖片類包含了一個圖片對象,用于控制對其加載和顯示的訪問。在主程序中,我們首先創(chuàng)建了一個真實的圖片對象,并使用代理圖片對象進行訪問。第一次訪問時,代理圖片對象會加載并顯示真實的圖片;第二次訪問時,代理圖片對象直接從緩存中獲取并顯示圖片。
六、適配器模式
適配器模式是指將不兼容接口的對象轉(zhuǎn)化為兼容接口的對象。這個模式非常適合那些需要改變接口而不影響原有代碼的場景。下面是一個使用適配器模式的例子:
class OldCalculator {
?operations(a, b, operation) {
? ?switch (operation) {
? ? ?case 'add':
? ? ? ?return a + b;
? ? ?case 'sub':
? ? ? ?return a - b;
? ? ?default:
? ? ? ?return NaN;
? ?}
?}
}
class NewCalculator {
?add(a, b) {
? ?return a + b;
?}
?sub(a, b) {
? ?return a - b;
?}
}
class CalculatorAdapter {
?constructor() {
? ?this.newCalculator = new NewCalculator();
?}
?operations(a, b, operation) {
? ?switch (operation) {
? ? ?case 'add':
? ? ? ?return this.newCalculator.add(a, b);
? ? ?case 'sub':
? ? ? ?return this.newCalculator.sub(a, b);
? ? ?default:
? ? ? ?return NaN;
? ?}
?}
}
const oldCalculator = new OldCalculator();
console.log(oldCalculator.operations(10, 5, 'add')); // 15
const newCalculator = new NewCalculator();
console.log(newCalculator.add(10, 5)); // 15
const calculatorAdapter = new CalculatorAdapter();
console.log(calculatorAdapter.operations(10, 5, 'add')); // 15
上述代碼中,我們創(chuàng)建了一個舊計算器類 OldCalculator 和一個新計算器類 NewCalculator。然后,我們創(chuàng)建了一個適配器類 CalculatorAdapter,該類包含了一個新計算器對象,用于將舊計算器的操作轉(zhuǎn)化為新計算器的操作。在主程序中,我們分別使用舊計算器、新計算器和適配器進行加法運算,并得到了相同的結(jié)果。
七、命令模式
命令模式是指將請求封裝成一個對象,并提供與執(zhí)行該請求相關(guān)的所有信息。這個模式非常適合那些需要執(zhí)行多個不同操作的場景。下面是一個使用命令模式的例子:
class Receiver {
?run() {
? ?console.log('Receiver is running.');
?}
}
class Command {
?constructor(receiver) {
? ?this.receiver = receiver;
?}
?execute() {}
}
class StartCommand extends Command {
?execute() {
? ?this.receiver.run();
?}
}
class Invoker {
?setCommand(command) {
? ?this.command = command;
?}
?executeCommand() {
? ?this.command.execute();
?}
}
const receiver = new Receiver();
const startCommand = new StartCommand(receiver);
const invoker = new Invoker();
invoker.setCommand(startCommand);
invoker.executeCommand(); // Receiver is running.
上述代碼中,我們創(chuàng)建了一個接收者類 Receiver 和一個命令基類 Command。然后,我們創(chuàng)建了一個具體命令類 StartCommand,該類繼承自命令基類,并實現(xiàn)了執(zhí)行方法 execute,用于啟動接收者。最后,我們創(chuàng)建了一個調(diào)用者類 Invoker,該類包含了一個命令對象,并提供了執(zhí)行命令的方法。在主程序中,我們創(chuàng)建了一個接收者對象、一個具體命令對象和一個調(diào)用者對象,并將具體命令對象設(shè)置為調(diào)用者對象的命令。然后,我們執(zhí)行調(diào)用者對象的執(zhí)行方法,該方法會調(diào)用具體命令對象的執(zhí)行方法,從而啟動接收者。這個例子比較簡單,但命令模式可以應(yīng)用于很多復(fù)雜的場景,例如撤銷/恢復(fù)操作、事務(wù)管理等。
八、觀察者模式
觀察者模式是指在對象之間定義一種一對多的依賴關(guān)系,使得每當(dāng)一個對象改變狀態(tài)時,所有依賴于它的對象都會得到通知并自動更新。這個模式非常適合那些需要在應(yīng)用中實現(xiàn)事件處理的場景。下面是一個使用觀察者模式的例子:
class Subject {
?constructor() {
? ?this.observers = [];
?}
?addObserver(observer) {
? ?this.observers.push(observer);
?}
?removeObserver(observer) {
? ?const index = this.observers.indexOf(observer);
? ?if (index >= 0) {
? ? ?this.observers.splice(index, 1);
? ?}
?}
?notifyObservers() {
? ?for (const observer of this.observers) {
? ? ?observer.update(this);
? ?}
?}
}
class ConcreteSubject extends Subject {
?constructor(state) {
? ?super();
? ?this.state = state;
?}
?getState() {
? ?return this.state;
?}
?setState(state) {
? ?this.state = state;
? ?this.notifyObservers();
?}
}
class Observer {
?update() {}
}
class ConcreteObserver extends Observer {
?update(subject) {
? ?console.log(`The subject has changed to ${subject.getState()}.`);
?}
}
const subject = new ConcreteSubject('state1');
const observer1 = new ConcreteObserver();
const observer2 = new ConcreteObserver();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.setState('state2'); // The subject has changed to state2.
上述代碼中,我們創(chuàng)建了一個主題基類?Subject
?和一個具體主題類?ConcreteSubject
。主題類包含了一個狀態(tài)屬性和一組觀察者對象,并提供了方法以添加、刪除和通知觀察者。然后,我們創(chuàng)建了一個觀察者基類?Observer
?和一個具體觀察者類?ConcreteObserver
,該類繼承自觀察者基類,并實現(xiàn)了更新方法。在主程序中,我們創(chuàng)建了一個具體主題對象、兩個具體觀察者對象,并將觀察者對象添加到主題對象中。然后,我們修改了主題對象的狀態(tài),并通過主題對象通知觀察者對象進行更新操作。
以上就是八種常見的設(shè)計模式以及它們的應(yīng)用場景和示例代碼。當(dāng)然,這只是冰山一角,還有很多其他的設(shè)計模式可以應(yīng)用于不同的場景。熟悉各種設(shè)計模式并且能夠靈活運用它們可以讓你成為更優(yōu)秀的開發(fā)者。
今天的分享就到這里,感謝你的閱讀,希望能夠幫助到你,
文章創(chuàng)作不易,如果你喜歡我的分享,別忘了點贊轉(zhuǎn)發(fā),讓更多有需要的人看到,最后別忘記關(guān)注UP主,你的支持將是我分享最大的動力,后續(xù)我會持續(xù)輸出更多內(nèi)容,敬請期待
同時準(zhǔn)備了豐厚的學(xué)習(xí)資料來幫助大家的學(xué)習(xí)?需要的小伙伴找找up主領(lǐng)取即可
up主不主動聯(lián)系大家哦~需要的小伙伴后臺打招呼即可?