Reputation: 788
I've been reading the clean code book which ask for eliminate using switch case, So I wanted to implement it in JavaScript, and I wanted to use it in functional programming way, so I decided to use pattern matching.
I have the code below, that I want to omit the switch case, how can I do it, not using the polymorphism.
function calculateSalary(role) {
switch (true) {
case /CTO/.test(role):
return getCTOSallary();
case /CEO/.test(role):
return getCEOSallary();
case /engineer/.test(role):
return getEngineeringSallary();
default:
return getGeneralSallary();
}
}
Upvotes: 1
Views: 731
Reputation: 18921
Disclaimer: I am the author of the library mentioned in this answer.
I like the way it is done in Clojure with multimethods:
A Clojure multimethod is a combination of a dispatching function, and one or more methods.
The library @customcommander/multifun is an attempt at bringing multimethods to JavaScript.
You first need a dispatching function
This will be getRole
. It returns the part you're interested in or null
if the role is unknown:
const getRole = role => {
const match = role.match(/(cto|ceo|engineer)/i);
return match ? match[1].toLowerCase() : null;
};
Then you'll need a series of value/function pairs
'cto'
, getCTOSalary
'ceo'
, getCEOSalary
Finally you need a function when there are no matches
This will be the getGeneralSalary
function.
How does it work?
getRole
is the dispatching function, it is applied to the parameters and returns a valuevalue/function
pair.getGeneralSalary
is applied to the parameters when there are no matches.const multifun = require("@customcommander/multifun");
const getCTOSalary = (_, {bonus = 0}) => 10 + bonus;
const getCEOSalary = (_, {bonus = 0}) => 20 + bonus;
const getEngineeringSalary = (_, {bonus = 0}) => 30 + bonus;
const getGeneralSalary = (_, {bonus = 0}) => 40 + bonus;
const getRole = role => {
const match = role.match(/(cto|ceo|engineer)/i);
return match ? match[1].toLowerCase() : null;
};
const calculateSalary =
multifun
( getRole
, 'cto', getCTOSalary
, 'ceo', getCEOSalary
, 'engineer', getEngineeringSalary
, getGeneralSalary
);
calculateSalary('Chief Technology Officer (CTO)', {bonus: 1}); //=> 11
calculateSalary('Chief Executive Officer (CEO)', {bonus: 2}); //=> 22
calculateSalary('Senior Software Engineer', {bonus: 3}); //=> 33
calculateSalary('random title', {bonus: 4}); //=> 44
Upvotes: 1
Reputation: 74234
One way to do so would be to use dynamic dispatch.
const Engineer = (name, bonus) => ({ constructor: Engineer, name, bonus });
Engineer.calculateSalary = engineer => 20 + engineer.bonus;
const Employee = (name, bonus) => ({ constructor: Employee, name, bonus });
Employee.calculateSalary = employee => 10 + employee.bonus;
const calculateSalary = role => role.constructor.calculateSalary(role);
console.log("John's salary is", calculateSalary(Engineer("John", 10))); // 30
console.log("Mary's salary is", calculateSalary(Employee("Mary", 10))); // 20
Note that we could have used classes for dynamic dispatch too. However, I wanted to show that it's possible to have dynamic dispatch without using classes, using a purely functional style of programming.
Upvotes: 2
Reputation: 14904
Do you mean something like this?
function test(str) {
let tests = [/xyz/, /test/, /ing/];
if(tests.some(patt => patt.test(str))) {
console.log("Match found");
}else {
console.log("No match found");
}
}
test("testing");
Upvotes: 0