JavaScript 设计模式之策略模式

114 阅读2分钟

纯JavaScript版本的设计模式之策略模式。

定义

定义一组策略,将每种策略单独封装起来,根据相应的场景相互切换,从而实现策略的实现和使用分离开来。

是一种行为型设计模式。

实践

使用不同的分段方法将一段范围([min, max])分割成几段(count)。

形式一:函数形式的策略对象

实现:定义策略对象,用函数将每种策略封装起来。

// 分段方法
const ArrayStatistic = {
    // 等距分段
    equalIntervalBreaks: (count: number, max: number, min: number): number[] => {
        const breaks = [min];
        const breakSize = (max - min) / count;
        for (let i = 1; i < count; i++) {
            breaks.push(breaks[i - 1] + breakSize);
        }
        breaks.push(max);
        return breaks;
    },
    // 对数分段
    logarithmBreaks: (count: number, max: number, min: number): number[] => {
        const logMax = Math.log(max) / Math.LN10;
        const logMin = Math.log(min) / Math.LN10;
        const breaks = ArrayStatistic.equalIntervalBreaks(count, logMax, logMin);
        return breaks.map((value) => 10 ** value);
    },
    // 平方根分段
    sqrtBreaks: (count: number, max: number, min: number): number[] => {
        const sqrtMax = Math.sqrt(max);
        const sqrtMin = Math.sqrt(min);
        const breaks = ArrayStatistic.equalIntervalBreaks(count, sqrtMax, sqrtMin);
        return breaks.map((value) => value * value);
    }
};

使用:

const strategy = (type, count, max, min) {
    return ArrayStatistic[type](count, max, min);
}
strategy('equalIntervalBreaks', 2, 10, 2);
strategy('logarithmBreaks', 2, 10, 2);

形式二:高阶函数

实现三种策略:

// 等距分段
const equalIntervalBreaks = (count: number, max: number, min: number): number[] => {
    const breaks = [min];
    const breakSize = (max - min) / count;
    for (let i = 1; i < count; i++) {
        breaks.push(breaks[i - 1] + breakSize);
    }
    breaks.push(max);
    return breaks;
},
// 对数分段
const logarithmBreaks = (count: number, max: number, min: number): number[] => {
    const logMax = Math.log(max) / Math.LN10;
    const logMin = Math.log(min) / Math.LN10;
    const breaks = ArrayStatistic.equalIntervalBreaks(count, logMax, logMin);
    return breaks.map((value) => 10 ** value);
},
// 平方根分段
const sqrtBreaks = (count: number, max: number, min: number): number[] => {
    const sqrtMax = Math.sqrt(max);
    const sqrtMin = Math.sqrt(min);
    const breaks = ArrayStatistic.equalIntervalBreaks(count, sqrtMax, sqrtMin);
    return breaks.map((value) => value * value);
}

使用:

// 高阶函数
const strategy = (fn, count, max, min) {
    return fn(count, max, min);
}
strategy(equalIntervalBreaks, 2, 10, 2);
strategy(logarithmBreaks, 2, 10, 2);

个人Tip:实践开发中常用的是形式一,策略模式是预设计好的,有新增策略就新增函数, 策略对象新增type;形式二更易于扩展,新增函数,使用的地方传函数就好了, 更适用于明确传哪种策略函数, 如果外层还需要判断什么情况选用哪种策略,形式一更合适,个人见解, 大家可以根据应用场景选择适用的形式。

重构

在实际开发中,如果发现一个函数里:

1、条件判断多;

2、每个条件间互不影响;

就可以开始重构了:

1、各个条件单独封装成函数

2、建立判断条件和具体实现之间的映射关系(策略对象)。

快去试试吧,搜索代码中的else if ,或者 switch case,用策略模式重构函数, 让代码优雅起来。

总结

JavaScript中的策略模式常常是用函数去封装、实现。