首页 > 其他分享 >前端宝典十六:深入浅出8大设计模式

前端宝典十六:深入浅出8大设计模式

时间:2024-08-24 12:21:46浏览次数:13  
标签:代码 const void 深入浅出 宝典 console new 设计模式 class

本文主要探讨前端开发中的各种设计模式,主要分类有:

  • 单例模式
  • 建造者模式
  • 代理模式
  • 装饰器模式
  • 适配器模式
  • 策略模式
  • 观察者模式
  • 发布订阅模式

通过对他们实际开发中的使用场景的解析,深入浅出的一起更全面直观的进行学习:

一、单例模式

介绍

单例模式确保一个类只有一个实例,并提供一个全局访问点。

实际使用场景

实现全局唯一的状态管理,如全局配置对象、日志记录器等。

优点

  • 减少系统资源开销,因为只创建一个实例。
  • 提供全局访问点,方便在不同部分的代码中使用。

缺点

  • 违反单一职责原则,因为单例类可能承担过多的职责。
  • 可能会导致代码的紧耦合,因为其他部分的代码都依赖于这个单例。

代码实现1

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 来获取唯一的实例。如果实例不存在则创建一个新的实例并保存起来,下次调用时直接返回已有的实例。

代码实例2

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
}

这样通过Elementloading的时候,如果同时调用两次,只有一个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,通过不同的方法逐步构建产品的各个部分,最后返回构建好的产品。

三、代理模式

介绍

为其他对象提供一种代理以控制对这个对象的访问。

实际使用场景

  • 图片懒加载、数据预加载。
  • 权限控制等。

优点

  • 可以在不改变目标对象的情况下,为其添加额外的功能。
  • 可以控制对目标对象的访问,提高安全性和性能。

缺点

  • 增加了代码的复杂性,需要创建代理对象。
  • 可能会影响性能,因为代理对象需要进行额外的处理。

代码实现

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 类将旧库的接口转换为新的接口,使得可以在新的代码中使用旧库的功能。

六、策略模式

介绍

定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。

实际使用场景

  • 表单验证、排序算法选择等。
  • 当出现很多if-else或者switch时可以考虑使用策略模式

优点

  • 易于扩展和维护,当需要添加新的算法时,只需要创建一个新的策略类。
  • 可以在运行时动态地切换算法。

缺点

  • 增加了代码的复杂性,需要创建多个策略类。
  • 客户端需要了解不同的策略,增加了客户端的复杂度。

代码实现

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 方法发布事件,触发订阅者的回调函数。

标签:代码,const,void,深入浅出,宝典,console,new,设计模式,class
From: https://blog.csdn.net/franktaoge/article/details/141497274

相关文章

  • 设计模式(三)
    结构型模式装饰器模式:动态的给一个对象增加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。优/缺点:装饰模式是继承关系的一个替代方案。装饰模式可以动态地扩展一个实现类的功能。缺点:多层的装饰还是比较复杂何时使用:需要扩展一个类的功能,或给一个类增加附加功......
  • 设计模式概述和设计原则
    1.设计模式的概念软件设计模式(SoftwareDesignPattern),是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具......
  • 设计模式[4]-建造者模式
    代码:https://gitee.com/Aes_yt/design-pattern建造者模式建造者模式是将一个复杂对象,解构为多个简单的对象,然后一步一步慢慢构造成原对象。建造者模式主要包括四种角色:抽象建造者:具有产品的多个子部件的抽象接口,最终可以返回完整产品具体建造者:对抽象建造者的实现,有多个子......
  • 设计模式[3]-原型模式
    代码:https://gitee.com/Aes_yt/design-pattern原型模式概念原型模式将一个已经创建的实例作为原型,复制出一个和原型相同的新对象。包括三种角色:抽象原型:抽象角色,提供具体原型需要实现的接口具体原型:被复制的对象,实现抽象原型的接口客户端:发出创建对象的请求。例子:先......
  • 设计模式[2]-工厂模式
    代码:https://gitee.com/Aes_yt/design-pattern工厂模式1.简单工厂模式简单工厂模式主要包括三种角色:简单工厂:创建具体产品抽象产品:具体产品的父类具体产品:简单工厂创建的对象例子:设计一个游戏机类(GameConsole)作为抽象产品,然后设计具体的产品(PlanStation4,Xb......
  • 设计模式[1]-单例模式
    代码:https://gitee.com/Aes_yt/design-pattern单例模式单例模式(Singleton)是一种创建型设计模式,能够保证一个类只有一个实例,并提供了访问该实例的全局节点。单例的实现步骤有以下步骤,首先将默认构造函数设置为私有,然后创建一个静态方法来调用私有构造函数来创建对象。单例类......
  • C++设计模式1:单例模式(懒汉模式和饿汉模式,以及多线程问题处理)
    饿汉单例模式        程序还没有主动获取实例对象,该对象就产生了,也就是程序刚开始运行,这个对象就已经初始化了。 classSingleton{public: ~Singleton() { std::cout<<"~Singleton()"<<std::endl; } staticSingleton*get_instance() { return&sin......
  • Java设计模式之代理模式:静态代理VS动态代理,与其他模式的对比分析和案例解析
    一、代理模式简介代理模式(ProxyPattern)是一种结构型设计模式,它提供了一个代理对象,用来控制对另一个对象的访问。这种模式通常用于在访问对象时引入额外的功能,而不改变对象的接口。代理模式的核心思想是为其他对象提供一种代理,以控制对这个对象的访问。在现实生活中,代理模......
  • 设计模式之责任链模式
    责任链模式是面向对象的23种设计模式中的一种,属于行为模式范围。责任链模式(ChainofResponsibility),见名知意:就是每一个处理请求的处理器组合成一个链表,链表中的每个节点(执行器)都有机会处理发送的请求。大致的结构是这个样子: 举一个简单的例子:某公司有一名新员工要入职,则入职......
  • 设计模式简介及PHP的35种设计模式(上)
    什么是模式??        有经验的00开发者(以及其他的软件开发者)建立了既有通用原则又有惯用方案的指令系统来指导他们编制软件。如果以结构化形式对这些问题、解决方案和命名进行描述使其系统化,那么这些原则和习惯用法就可以称为模式。例如,下面是一个模式样例:    ......