W artykule przedstawię alternatywę dla użycia bloku if/else oraz switch. Kod napisany w ten sposób będzie przyjemny w odbiorze, dodawanie kolejnych warunków jak również ich modyfikacja też nie powinna stanowić problemu. Zachęcam do przeczytania, być może wdrożycie takie podejście w Waszych projektach.

Przykład wraz z kodem

Przyjmijmy, że musimy policzyć bonus/zniżkę na podstawie typu użytkownika. W tym celu utworzymy funkcję getBonus(), która będzie liczyła nam końcowy wynik.

export const getBonus = (user) =>
{
    if (user.type == 'standard') {
        // logika
        return 10;
    } else if (user.type == 'premium') {
        // logika
        return 20;
    } else if (user.type == 'vip') {
        // logika
        return 30;
    }

    // logika default
    return 0;
}

Wszystko wydaje się być oczywiste, przekazujemy typ usera, liczymy bonus i zwracamy wartość. Jeżeli typów klientów będzie więcej, pierwsze co przychodzi na myśl to użycie switch zamiast if oraz else, co trochę poprawi czytelność. Kolejnym krokiem mogłoby być wyniesienie logiki do oddzielnych funkcji. Całość mogłaby wyglądać mniej więcej w ten sposób.

export const getBonus = (user) =>
{
    switch (user.type) {
        case 'standard':
            return getBonusStandardUserType(user);
        case 'premium':
            return getBonusPremiumUserType(user);
        case 'vip':
            return getBonusVipUserType(user);
        default:
            return getBonusDefaultUserType(user);
    }
}

W ten sposób logika dla poszczególnego typu klienta znajduje się wewnątrz funkcji, łatwiej możemy przetestować funkcję i to, czy zwraca ona poprawne dane. Poprawiła się też czytelność kodu.

Spróbujmy jeszcze zmodyfikować funkcję, aby uniknąć bloku switch. Przenieśmy teraz kod wraz z funkcjami do obiektu, usuwając całkowicie switch.

const conditions = {
    standard: getBonusStandardUserType,
    premium: getBonusPremiumUserType,
    vip: getBonusVipUserType,
    default: getBonusDefaultUserType
};

Teraz możemy wywołać już funkcję korzystając z obiektu i właściwości, do której przypisana jest odpowiednia funkcja.

return conditions[user.type](user);

Żeby bardziej przybliżyć jak „działa” taki zapis, można przyjrzeć się poniższemu fragmentowi.

// zwracamy odpowiednia funkcje z logika
const functionCondition = conditions[user.type]; 

return functionCondition (user);

Pozostała jeszcze jedna kwestia do rozwiązania, mianowicie obsługa przypadku, w którym przekażemy typ usera, dla którego nie jest zdefiniowana żadna logika, czyli w tym przypadku default.

Skorzystajmy w tym celu z in, który sprawdzi czy dla danego obiektu żądana właściwość jest dostępna.
Więcej na temat wyrażenia in znajdziemy tutaj: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in

(user.type in conditions) // true / false

Zapis taki zwróci nam true albo false, w zależności czy obiekt conditions posiada zdefiniowaną właściwość. Dla naszego przypadku będzie to zdefiniowana funkcja w zależności od typu klienta.

(user.type in conditions) ? conditions[user.type] : conditions.default)

Powyższy kod zapewni nam już obsługę zwrócenia odpowiedniej funkcji albo funkcji domyślnej – conditions.default, w sytuacji gdy typ użytkownika nie ma zdefiniowanej logik – gdy właściwość nie występuje w obiekcie conditions.

Pozostało nam jeszcze wywołanie zwróconej funkcji z odpowiednim argumentem. Zwróćcie proszę uwagę na nawiasy.

return ((user.type in conditions) ? conditions[user.type] : conditions.default)(user);

Całość funkcji mogłaby wyglądać następująco:

export const getBonus = (user) =>
{
    const conditions = {
        standard: getBonusStandardUserType,
        premium: getBonusPremiumUserType,
        vip: getBonusVipUserType,
        default: getBonusDefaultUserType
    };

    return ((user.type in conditions) ? conditions[user.type] : conditions.default)(user);
}

W mojej opinii kod taki wygląda bardziej czytelnie niż użycie wielu if, else if, else lub bloku switch. Wybór zostawiam jednak Wam. Mimo wszystko mam nadzieję, że przyda Wam się ta wiedza i gdzieś zostanie użyta.

Źródła:
Obraz: https://unsplash.com/photos/JZyJxeCBtF4