JavaScript 设计模式 - 充当管理器并调用不同方法的方法

JavaScript Design Patterns - Method which behaves as a manager and call different methods

简介

我的应用程序有不同的功能,例如:

  1. 重设密码(忘记密码)
  2. 更新用户密码
  3. 注册
  4. 成为溢价

对于每个功能,当成功时,我想向用户发送自定义 HTML 电子邮件。

生成电子邮件

由于HTML主要结构相同(只是内容(文本)发生变化),我决定实现我的辅助方法generateEmailTemplate():

const { HEAD, BODY } = require("../utils");

module.exports = (main) => `
  <!DOCTYPE html>
  <html lang="en">
    ${HEAD}
    ${BODY(main)}
  </html>
`;

并且,为了将特定数据包含到生成的模板中,我对每个功能使用不同的方法:

const signUpWelcomeEmailTemplate = (name) => 
  templateGenerator(`<p>Welcome, ${name}</p>`);

const premiumEmailTemplate = (name) =>
  templateGenerator(`<h1>${name}, you are now premium!</h1>`); 

// The html is more complex, I have reduced it for simiplicity

正在发送电子邮件

为了向用户发送电子邮件,我有以下方法,它将电子邮件记录添加到我的数据库中。然后,当添加记录时,连接到 MailGun 服务的自定义扩展通过 SMTP 发送邮件。

这是我的方法的实现:

async function sendEmail(
  to,
  subject,
  text = undefined,
  html = undefined
) {
  const mailsRef = db.collection("mails");

  const mail = {
    to,
    message: {
      subject,
      ...text && { text },
      ...html && { html },
    },
  };

  await mailsRef.add(mail);

  functions.logger.log("Queued email for delivery!");
};

问题

现在,为了使用此方法,在每个功能中,我必须执行以下操作:

async function goPremium(user) {
   try {
     await purchasePremium(user.uid);

     const html = premiumEmailTemplate(user.name);

     sendEmail(user.email, "Premium purchase success!", undefined, html);
   } catch(err) {
     ...
   }
}

我正在寻找一种概括此调用的模式,我的意思是,某种电子邮件管理器。

我想过两种不同的方法来重构这段代码:

#1(我不喜欢这种方式,因为方法可能超长,我的意思是,想象一下 100 个特征...)

   function emailManager(user, type) {
     switch(type) {
       "welcome":
         sendEmail(user.email, "Welcome!", undefined, welcomeEmailTemplate(user.name));
         break;

       "premium":
         sendEmail(user.email, "Premium purchase success!", undefined, premiumEmailTemplate(user.name));
         break;

       default:
         break;
     }
   }
  1. 只需创建不同的方法并从 'central' 模块导出它们。
...

const sendPremiumEmail = (user) => {
  const title = "Premium purchase success!";
  const html = premiumEmailTemplate(user.name);
  
  return sendEmail(user.email, title, undefined, html);
};

...

module.exports = {
  sendWelcomeEmail,
  sendPremiumEmail,
  ...
}

但是...也许还有另一种方法,一种模式可以完全解决这种情况。有什么想法吗?

函数式风格 -- 定义 curried 函数 sendEmail 并为高级电子邮件和欢迎电子邮件制作两个部分应用程序。

const sendEmail = (subject, template) => to => {
  const mailsRef = db.collection("mails");
  const html = template(to);
  const mail = {
    to,
    message: {
      subject,
      ...text && { text },  // unused
      ...html && { html },
    },
  };
  await mailsRef.add(mail);
  functions.logger.log("Queued email for delivery!");
}

const sendPremiumEmail = sendEmail("Premium purchase success!", premiumEmailTemplate);
const sendWelcomeEmail = sendEmail("Welcome", welcomeEmailTemplate);

// usage
await sendPremiumEmail('foo@email.com');