Введение

В данной статье будет рассмотрен паттерн CustomSwitch, который может быть использован в различных ситуациях и программных языках. В данном случае мы реализуем CustomSwitch на языке программирования JavaScript. Однако, стоит помнить, что это далеко не единственный возможный язык для его реализации.

Использование

Первый скриншот демонстрирует код игрового движка. На втором примере, я приведу код автора и свой код, в котором используется паттерн CustomSwitch.

Код автора:

nextPosition(initialX, initialY, direction) {
    let x = initialX;
    let y = initialY;
    let size = gameConfig.TILE_SIZE;

    if (direction == 'right') {
        x += size;
    } else if (direction == 'left') {
        x += -size;
    } else if (direction == 'up') {
        y += -size;
    } else if (direction == 'down') {
        y += size;
    }

    return { x, y };
}

Мой код:

// значения координат игрока/игрового обьекта и его направление.
nextPosition(initialX, initialY, direction) {
    // Что нам нужно изменить
    let change = {
        x: new Number(initialX).valueOf(),
        y: new Number(initialY).valueOf(),
        size: gameConfig.TILE_SIZE
    }

    // направления игрока, массив где первый элемент какую координату изменить в change обьекте, второй эелемент это размер тайла в положительно либо отрицательном значении
    let match = {
        left : ['x', -change.size],
        right: ['x', change.size],
        up   : ['y', -change.size],
        down : ['y', change.size]
    }

    // обращаемся к обьекту где мы изменяем значение что нам дает в массиве первого эелмента и прибавляем значение размера тайла в положительном либо отрицательном значении.
    change[match?.[direction][0]] += match?.[direction][1];
    return { x: change.x, y: change.y };
}

В обоих примерах функция nextPosition принимает начальные координаты (initialX и initialY) и направление (direction), и возвращает новые координаты.

Первый код без паттерна CustomSwitch использует условные операторы if и else if для определения значения координат x и y в зависимости от направления. Здесь каждое условие проверяет, равно ли значение direction определенному направлению, и, в случае совпадения, изменяет соответствующую координату.

Второй код с паттерном CustomSwitch использует объект change, который содержит начальные значения координат x, y и размер size. Затем создается объект match, который представляет собой ассоциативный массив, где ключами являются направления, а значениями - массивы, содержащие изменяемую координату и величину изменения.

Далее, с использованием сокращенного синтаксиса опциональной цепочки и опционального оператора, происходит выбор соответствующей пары координат и величины изменения на основе направления. Затем происходит изменение соответствующей координаты, используются значения из match, и полученные новые значения координат присваиваются в объект change.

В итоге, функция возвращает измененные значения координат x и y в виде объекта.

Принцип / механика

Принцип и механика паттерна CustomSwitch имеют следующую структуру:

  1. Паттерн основан на объектах, которые представляют кастомные случаи (case блоки).

  2. Код становится более читабельным, так как используется объектная структура вместо условий if else.

  3. Этот паттерн может быть полезен, когда требуется изменить или выполнить другие действия в задаче.

Паттерн CustomSwitch может заменить использование условий if else. Если бы был использован стандартный switch, это могло бы привести к повышению количества строк кода и ухудшению его читабельности. Однако данный паттерн способен упростить разработку, обеспечивая более гибкую альтернативу при решении задачи.

Реализация

Давайте создадим функцию changeArray, которая будет изменять массив с помощью переданных функций и аргументов.

/**
 * Изменяет входной массив с помощью переданных функций и аргументов
 * @param {array} list - входной массив
 * @param {string} func - имя функции для изменения массива
 * @param {any} argument - дополнительный аргумент для функции
 * @returns {array} - измененный массив
 * @throws {string} - если аргумент не является массивом
**/
function changeArray(list, func, argument) {
    if (!Array.isArray(list)) {
        throw `The argument is not an Array: ${list}`;
    }

    let [response, argumentsList] = [, [list, argument]];

    // код, выполняющий изменение массива

    return response;
}

Теперь давайте добавим колбэки в объект callbacks, которые будут выполнять операции с массивами.

let callbacks = {
    /**
     * Сливает два массива в один
     * @param {array} l1 - первый массив
     * @param {array} l2 - второй массив
     * @returns {array} - объединенный массив
    **/
    merge: (l1, l2) => l1.concat(l2),

    /**
     * Преобразует массив в вектор, заменяя значения на 0
     * @param {array} l - входной массив
     * @param {number} a1 - дополнительный аргумент
     * @returns {array} - массив-вектор со значениями 0
    **/
    vector: (l, a1) => callbacks.multiply(l, a1 ?? 0).map(v => [v]),

    /**
     * Преобразует массив в вектор, оставляя значения без изменений
     * @param {array} l - входной массив
     * @returns {array} - массив-вектор без изменений
    **/
    toVector: (l) => callbacks.vector(l, 1)
};

let args = {
    merge: argumentsList,
    vector: [list],
    toVector: [list]
};

Затем мы вызываем соответствующий колбэк с передачей аргументов, если он существует, и возвращаем null, если колбэк не существует.

let callback = callbacks?.[func];
response = callback ? args?.[func] ? callback(...args[func]) : callback() : null;

Наконец, после определения функций, мы можем выполнить операции с массивом:

console.log(changeArray([1, 2], 'merge', [2, 3]));
console.log(changeArray([1, 2], 'vector'));
console.log(changeArray([1, 2], 'toVector'));

Результат:

[ 1, 2, 2, 3 ]
[ [ 0 ], [ 0 ] ]
[ [ 1 ], [ 2 ] ]
полный код
function changeArray(list, func, argument) {
    if (!Array.isArray(list)) throw `The argument is not a Array: ${list}`;
    let [response, argumentsList] = [, [list, argument]];

    let callbacks = {
        mul: (l, a1) => l.map(v => v * a1),
        sub: (l, a1) => l.map(v => v - a1),
        merge: (l1, l2) => l1.concat(l2),
        vector: (l, a1) => callbacks.mul(l, a1 ?? 0).map(v => [v]),
        toVector: (l) => callbacks.vector(l, 1)
    }

    let args = {
        mul: argumentsList,
        sub: argumentsList,
        merge: argumentsList,
        vector: [list],
        toVector: [list]
    }

    let callback = callbacks?.[func];
    response = callback ? args?.[func] ? callback(...args[func]) : callback() : null;

    return response;
}


console.log(changeArray([1, 2], 'merge', [2, 3]));
console.log(changeArray([1, 2], 'vector'));
console.log(changeArray([1, 2], 'toVector'));

Заключение

В данной статье был рассмотрен паттерн CustomSwitch и его возможная реализация. Мы рассмотрели важные аспекты работы с этим паттерном и ознакомились с примерами его применения.

CustomSwitch представляет собой полезный инструмент для разработчиков, который позволяет создавать настраиваемые переключатели с использованием пользовательских элементов управления. Этот паттерн особенно полезен в случаях, когда требуется реализовать сложную логику переключения или когда требуется дополнительная настройка внешнего вида переключателя.

Мы обсудили несколько важных моментов, которые следует учитывать при реализации CustomSwitch. Во-первых, необходимо правильно определить интерфейс для нашего переключателя, чтобы пользователь мог легко использовать его в своем коде. Во-вторых, необходимо предусмотреть возможность настройки внешнего вида переключателя через параметры или методы. Наконец, для удобства использования паттерна, можно предоставить вспомогательные методы или классы, которые облегчат работу с CustomSwitch.

Важно отметить, что понимание принципов работы с CustomSwitch приходит с опытом в кодинге. Чем больше вы будете использовать этот паттерн и применять его в своих проектах, тем лучше вы сможете освоить его возможности и настроить его под свои потребности.

В завершение статьи, надеюсь, что вы получили удовольствие от ее прочтения и приобрели новые знания о паттерне CustomSwitch. Мы надеемся, что вы сможете успешно применить его в своих проектах и усовершенствовать свои навыки в разработке программного обеспечения.

Комментарии (7)


  1. CoolCmd
    20.10.2023 19:45
    +18

    new Number(initialX).valueOf()

    это что за индусский код?

    Второй пример кода более компактный и читабельный.
    change[match?.[direction][0]] += match?.[direction][1];

    читабельный - нет.


    1. space2pacman
      20.10.2023 19:45

      Надо тогда уж

      const x = new Number(initialX).valueOf();
      
      if (x > 0 && x < Infinity && isNumber(x) && backupCheckIsExactlyIsTtheNumber(x)) {
        switch(x) {
            case 0: ...
            case 1_000_000: ...
        }
      }


  1. fransua
    20.10.2023 19:45
    +4

    Не знал, что для этого есть имя, хотя иногда использую.
    Но правда, откуда такой страшный код? Почему везде let? Зачем проверять на null то что инициализировано ровно перед вызовом? Как этот код вообще можно было написать?

    let [response, argumentsList] = [, [list, argument]];
    response = callback ? args?.[func] ? callback(...args[func]) : callback() : null;
    

    Почему это не заменено на return callbacks[func]?.(list, argument);
    Это очень плохая нейросеть писала?


    1. candyboah
      20.10.2023 19:45

      Кстати, Француа читается от слова Френсис.


  1. Fodin
    20.10.2023 19:45
    +6

    "Код автора" читается и понимается мгновенно. К нему не нужны комментарии. Правда, я бы через switch сделал. На "улучшении" я завис на минуту, наверное. Особенно прибалдел с new Number - это просто троллинг какой-то.
    Функция уже грязная, поэтому match стоит за функцию вынести, чтоб не создавался каждый раз. Тогда можно убрать size и возвращать сам change. И что произойдет, если direction не найдется в match? Такой вариант ведь предусматривается в функции, судя по "?.". Авторская функция к этому устойчива, как и switch.
    Двойной тернарник ниже не всякий линтер пропустит.


  1. Tzimie
    20.10.2023 19:45
    +1

    KISS


  1. FisHlaBsoMAN
    20.10.2023 19:45
    -1

    снова этот сумасшедший..