【02问:前端常见的设计模式】

一、策略模式

简单来说就是一个问题匹配多个解决方案,不一定使用哪个,而且后续可能会继续增加或减少方案。主要

目录

一、策略模式

二、单例模式

方法一:使用对象字面量

方法二:使用闭包

三、观察者模式

[方法一:使用 ES6 类](#方法一:使用 ES6 类)

方法二:使用函数和闭包

方法三:使用事件机制

四、工厂模式


解决在多种相似算法存在时,使用条件语句(如if...else)导致的复杂性和难以维护的问题。

例如,购物车满减:

  • 满100减10
  • 满200减20
  • 8折
  • ......

使用策略模式实现:

复制代码
<script>
        // 以闭包的形式把折扣方案保存
        const calcPrice = (function () {
            const sale = {
                '100_10': function (price) { return price -= 10 },
                '200_20': function (price) { return price -= 20 },
                '80%': function (price) { return price *= 0.8 },
            }

            // 计算折扣
            function calcPrice(price, type) {
                if(!sale[type]) return '没有这个折扣'
                return sale[type](price)
            }

            // 添加折扣
            calcPrice.add = function (type, fn) {
                if (sale[type]) return '折扣已经存在';
                sale[type] = fn
            }
            return calcPrice
        })()

        const res = calcPrice(200, '80%');
        console.log(res)
    </script>

二、单例模式

使用闭包是实现单例模式的一种常见方法。通过将类的实例保存在闭包中,并提供一个公共方法来获取该实例,可以确保只有一个实例被创建和访问。

方法一:使用对象字面量

这种方法简单直接,通过对象字面量创建一个单例对象。

复制代码
const singleton = {
    property: 'value',
    method: function() {
        console.log('method called');
    }
};

// 使用
singleton.method(); // 输出: method called

方法二:使用闭包

闭包是一种强大的工具,可以用来创建私有变量和方法。

复制代码
const Singleton = (function() {
    let instance;

    function createInstance() {
        const object = new Object('I am the instance');
        return object;
    }

    return {
        getInstance: function() {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

// 使用
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // 输出: true

三、观察者模式

观察者模式(Observer Pattern)是一种行为设计模式,它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它会通知所有观察者对象,使它们能够自动更新自己。

在前端开发中,观察者模式非常适用于事件处理、数据绑定等场景。以下是实现观察者模式的几种常见方法:

方法一:使用 ES6 类

使用 ES6 的类语法,可以优雅地实现观察者模式。

复制代码
class Subject {
    constructor() {
        this.observers = [];
    }

    addObserver(observer) {
        this.observers.push(observer);
    }

    removeObserver(observer) {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

    notifyObservers(data) {
        this.observers.forEach(observer => observer.update(data));
    }
}

class Observer {
    update(data) {
        console.log('Observer received data:', data);
    }
}

// 使用
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notifyObservers('some data'); // 所有观察者都会收到更新

方法二:使用函数和闭包

如果不使用类,也可以通过函数和闭包来实现观察者模式。

复制代码
function createSubject() {
    let observers = [];

    function addObserver(observer) {
        observers.push(observer);
    }

    function removeObserver(observer) {
        observers = observers.filter(obs => obs !== observer);
    }

    function notifyObservers(data) {
        observers.forEach(observer => observer.update(data));
    }

    return {
        addObserver,
        removeObserver,
        notifyObservers
    };
}

function createObserver() {
    return {
        update(data) {
            console.log('Observer received data:', data);
        }
    };
}

// 使用
const subject = createSubject();
const observer1 = createObserver();
const observer2 = createObserver();

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notifyObservers('some data'); // 所有观察者都会收到更新

方法三:使用事件机制

前端的事件机制本身就很适合实现观察者模式,例如可以使用自定义事件。

复制代码
class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(event, listener) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(listener);
    }

    off(event, listener) {
        if (!this.events[event]) return;
        this.events[event] = this.events[event].filter(l => l !== listener);
    }

    emit(event, data) {
        if (!this.events[event]) return;
        this.events[event].forEach(listener => listener(data));
    }
}

// 使用
const emitter = new EventEmitter();

function listener1(data) {
    console.log('Listener 1 received:', data);
}

function listener2(data) {
    console.log('Listener 2 received:', data);
}

emitter.on('event', listener1);
emitter.on('event', listener2);

emitter.emit('event', 'some data'); // 所有监听器都会收到更新

emitter.off('event', listener1);
emitter.emit('event', 'some other data'); // 只有Listener 2 会收到更新

四、工厂模式

工厂模式(Factory Pattern)提供了一种创建对象的方式,使得创建对象的过程与使用对象的过程分离,而无需指定要创建的具体类。

通过使用工厂模式,可以将对象的创建逻辑封装在一个工厂类中,而不是在客户端代码中直接实例化对象,这样可以提高代码的可维护性和可扩展性。

复制代码
class VehicleFactory {
    static createVehicle(type, model) {
        switch(type) {
            case 'car':
                return new Car(model);
            case 'truck':
                return new Truck(model);
            default:
                throw new Error('Unknown vehicle type');
        }
    }
}

class Car {
    constructor(model) {
        this.model = model;
    }

    drive() {
        console.log(`${this.model} car is driving`);
    }
}

class Truck {
    constructor(model) {
        this.model = model;
    }

    drive() {
        console.log(`${this.model} truck is driving`);
    }
}

// 使用
const myCar = VehicleFactory.createVehicle('car', 'Toyota');
const myTruck = VehicleFactory.createVehicle('truck', 'Ford');

myCar.drive(); // 输出: Toyota car is driving
myTruck.drive(); // 输出: Ford truck is driving
相关推荐
小杨升级打怪中25 分钟前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
Yvonne爱编码38 分钟前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder
SuperherRo1 小时前
Web开发-JavaEE应用&SpringBoot栈&SnakeYaml反序列化链&JAR&WAR&构建打包
前端·java-ee·jar·反序列化·war·snakeyaml
大帅不是我1 小时前
Python多进程编程执行任务
java·前端·python
前端怎么个事1 小时前
框架的源码理解——V3中的ref和reactive
前端·javascript·vue.js
敲代码的 蜡笔小新1 小时前
【行为型之访问者模式】游戏开发实战——Unity灵活数据操作与跨系统交互的架构秘诀
unity·设计模式·c#·访问者模式
Ciito1 小时前
将 Element UI 表格元素导出为 Excel 文件(处理了多级表头和固定列导出的问题)
前端·vue.js·elementui·excel
不爱吃饭爱吃菜2 小时前
uniapp微信小程序一键授权登录
前端·javascript·vue.js·微信小程序·uni-app
heart000_12 小时前
从零开始打造个人主页:HTML/CSS/JS实战教程
javascript·css·html
90后小陈老师3 小时前
3D个人简历网站 5.天空、鸟、飞机
前端·javascript·3d