使用高阶函数的策略模式

使用高阶函数的策略模式
如果您的团队习惯于函数式编程,那么请知道也可以以功能性方式使用诸如Strategy模式之类的设计模式。

策略模式通常使用类来实现。 然而,可以以功能模式容易地实现。

通常,所有具有相同接口的策略对象都可以根据需要轻松进行交换。 这是策略模式的主要好处之一。

例如,如果您想发送电子邮件,但想实现一种在通过Sparkpost或通过AWS发送电子邮件之间进行更改的方法,则可以执行以下操作:

class EmailStrategy {
constructor() {}
execute(sender, receiver, subject, body) {
throw new Error('Not implemented');
}
}
class SparkPostEmailStrategy extends EmailStrategy {
constructor(apiKey, SparkPost) {
this.sparkpost = new SparkPost(apiKey);
}
execute(sender, receiver, subject, body) {
return this.sparkpost.transmissions.send({
content: {
from: sender,
subject,
html: body,
},
recipients: [
{address: sender}
]
});
}
}
class AWSEmailCommand extends IEmailCommand {
constructor(AWS) {
this.ses = new AWS.SES();
}
execute(sender, receiver, subject, body) {
return new Promise((resolve, reject) => {
this.ses.sendEmail({
Destination: {
ToAddresses: [receiver]
},
Message: {
Body: {
Html: {
Data: body,
},
},
Subject: {
Data: subject,
}
},
Source: sender,
}, (err, data) => {
if (err) reject(err);
resolve(data);
});
});
}
}

现在我们可以互换使用SparkPostEmailCommandAWSEmailCommand

const command = new SparkPostEmailCommand(myApiKey, SparkPost);
command.execute('[email protected]', '[email protected]', title, body)
.then((data) => console.log('success'))
.catch((err) => console.error('failure', err));

但是大多数Command对象只是两个方法:一个构造函数和一个execute方法(有时是undo方法)。 几乎感觉就像当我们调用构造函数时,我们只是在延迟执行execute方法直到希望它执行其副作用为止。

使用高阶函数

对我来说,这是一个使用高阶函数简化上面代码并消除对简单函数的类需求的好时机。

由于大多数时候,我们关心的只是建立一些依赖关系,然后延迟执行,因此我们可以将Command类编写为函数:

const sparkPostEmailCommand = (apiKey, SparkPost) => {
const sparkpost = new SparkPost(apiKey);
return (sender, receiver, subject, body) => {
return sparkpost.transmissions.send({
// Same as above
});
};
};
const awsEmailCommand = (AWS) => {
const ses = new AWS.SES();
return (sender, receiver, subject, body) => {
return new Promise((resolve, reject) => {
// Same as above
});
};
};

现在,除了创建新对象,我们还可以将命令用作函数:

sparkPostEmailCommand(myApiKey, SparkPost)('[email protected]', '[email protected]', title, body)
.then((data) => console.log('success'))
.catch((err) => console.error('failure', err));

或者我们可以延迟执行:

const execute = sparkPostEmailCommand(myApiKey);
// do some work
execute('[email protected]', '[email protected]', title, body);

为什么要使用高阶函数?

虽然其他语言的类可以为您提供类型提示和安全性,但JavaScript并非如此。 您真的不知道不幸的是,您execute方法的所有签名看起来都一样。

而且,无需键入内容,就不需要添加类实现附带的所有功能。 为什么要担心this绑定? 还是extends BaseCommand

使用这些设计模式的目的并不是要使它们面向对象。 这是因为它们可以帮助您使用通用模式来组织代码。 建立具有依赖关系的对象然后执行某些操作是一种常见的模式,其中“执行某些操作”可能以不同的方式完成。

如果您的团队习惯于使用类和对象,请使用类和对象。

如果您的团队习惯于函数式编程 ,那么您将知道像Command模式这样的设计模式也可以以函数方式使用。

Ivan Montiel是Clarity Hub的创始人兼首席执行官,该公司与Intercom集成,可在帮助客户时为您的Customer Success团队提供实时建议。
您可以在Twitter上关注他。

From: https://hackernoon.com/the-command-pattern-using-higher-order-functions-e482fe322460