赞
踩
本文主要探讨前端开发中的各种设计模式,主要分类有:
通过对他们实际开发中的使用场景的解析,深入浅出的一起更全面直观的进行学习:
单例模式确保一个类只有一个实例,并提供一个全局访问点。
实现全局唯一的状态管理,如全局配置对象、日志记录器等。
class Singleton { private static instance: Singleton; private constructor() {} public static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } public someMethod(): void { console.log('Singleton method called.'); } } const singleton1 = Singleton.getInstance(); const singleton2 = Singleton.getInstance(); console.log(singleton1 === singleton2); // true
通过静态方法 getInstance
来获取唯一的实例。如果实例不存在则创建一个新的实例并保存起来,下次调用时直接返回已有的实例。
element-ui对于全局loading的处理,使用的就是单例模式进行控制,每次只能触发一个全局loading
let fullscreenLoading; const loading = (options = {}) =>{ // options不传的话默认是fullscreen options = merge({}, defaults, options); if(options.fullscreen && fullscreenLoading){ return fullscreenLoading; // 存在直接return } let parent = options.body? document.body: options.target; let instance = new LoadingConstrutor({ el: document.createElement('div') }); if (options.fullscreen) { fullscreenLoading = instance } return instance }
这样通过Element
的loading
的时候,如果同时调用两次,只有一个loading
的遮罩层,不会有两个
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。目的是为了生成对象,把复杂的创建过程从构造函数分离出来,然后在不改变原有构造函数的基础上,创建各种各样的对象。
构建复杂的表单对象、配置对象等。
class Product { parts: string[] = []; addPart(part: string): void { this.parts.push(part); } } class Builder { buildPartA(): void { // 构建部分 A 的逻辑 } buildPartB(): void { // 构建部分 B 的逻辑 } getResult(): Product { const product = new Product(); product.addPart('Part A'); product.addPart('Part B'); return product; } } const builder = new Builder(); const product = builder.getResult(); console.log(product.parts);
Builder
类负责构建复杂对象 Product
,通过不同的方法逐步构建产品的各个部分,最后返回构建好的产品。
如果我们创建一个函数,参数不一定,为了方便以后的扩展,可以使用建造者模式,参数中传入默认值的方法:
function getPhone({
size,
screen = 'OLED',
price = 100,
discount = 10
}={}){
console.log('size', size);
console.log('screen', screen);
console.log('price', price);
console.log('discount', discount);
}
getPhone({size: 4, price: 200})
上面代码中通过传入参数默认值,很方便的设置参数,并且参数的顺序也不重要,未来在扩展的时候不需要担心太多地方调用传参是否会引起问题。
为其他对象提供一种代理以控制对这个对象的访问。
class RealImage { loadImage(): void { console.log('Loading real image.'); } } class ImageProxy { private realImage: RealImage | null = null; loadImage(): void { if (!this.realImage) { this.realImage = new RealImage(); } this.realImage.loadImage(); } } const proxy = new ImageProxy(); proxy.loadImage();
ImageProxy
代理了 RealImage
的加载操作,在实际需要加载图像时才创建真正的图像对象,实现了延迟加载。
动态地给一个对象添加一些额外的职责,而不改变其结构。
function logDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Calling method ${propertyKey}`); const result = originalMethod.apply(this, args); console.log(`Method ${propertyKey} finished`); return result; }; return descriptor; } class MyClass { @logDecorator myMethod(): void { console.log('Inside myMethod.'); } } const myObj = new MyClass(); myObj.myMethod();
装饰器函数 logDecorator
被安装到myMethod方案上,在myMethod调用前后添加了日志记录功能。
将一个类的接口转换成客户希望的另外一个接口。
class OldLibrary { oldMethod(): string { return 'Old library output'; } } class Adapter { private oldLibrary: OldLibrary; constructor() { this.oldLibrary = new OldLibrary(); } newMethod(): string { return `Adapted: ${this.oldLibrary.oldMethod()}`; } } const adapter = new Adapter(); console.log(adapter.newMethod());
Adapter
类将旧库的接口转换为新的接口,使得可以在新的代码中使用旧库的功能。
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
interface Strategy { execute(): void; } class ConcreteStrategyA implements Strategy { execute(): void { console.log('Executing strategy A.'); } } class ConcreteStrategyB implements Strategy { execute(): void { console.log('Executing strategy B.'); } } class Context { private strategy: Strategy; constructor(strategy: Strategy) { this.strategy = strategy; } setStrategy(strategy: Strategy): void { this.strategy = strategy; } executeStrategy(): void { this.strategy.execute(); } } const context = new Context(new ConcreteStrategyA()); context.executeStrategy(); context.setStrategy(new ConcreteStrategyB()); context.executeStrategy();
Context
类根据不同的策略对象执行不同的算法,通过设置不同的策略可以在运行时动态切换算法。
定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都将得到通知并自动更新。
class Subject { private observers: Observer[] = []; addObserver(observer: Observer): void { this.observers.push(observer); } removeObserver(observer: Observer): void { this.observers = this.observers.filter(obs => obs!== observer); } notifyObservers(): void { this.observers.forEach(observer => observer.update()); } } interface Observer { update(): void; } class ConcreteObserver implements Observer { update(): void { console.log('Observer notified.'); } } const subject = new Subject(); const observer1 = new ConcreteObserver(); const observer2 = new ConcreteObserver(); subject.addObserver(observer1); subject.addObserver(observer2); subject.notifyObservers();
Subject
维护一组观察者,当状态变化时通知所有观察者进行更新。
发布者和订阅者之间通过事件进行通信,发布者发布事件,订阅者订阅感兴趣的事件并在事件发生时做出响应。
class EventEmitter { private events: { [eventName: string]: ((...args: any[]) => void)[] } = {}; on(eventName: string, callback: (...args: any[]) => void): void { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); } emit(eventName: string,...args: any[]): void { if (this.events[eventName]) { this.events[eventName].forEach(callback => callback(...args)); } } } const eventEmitter = new EventEmitter(); eventEmitter.on('eventName', (data) => { console.log(`Received event with data: ${data}`); }); eventEmitter.emit('eventName', 'Some data');
EventEmitter
类提供了订阅和发布事件的方法,订阅者通过 on
方法订阅事件,发布者通过 emit
方法发布事件,触发订阅者的回调函数。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。