重构实例-消息发送-添加转换方法-4

阿里云短信发送API(SendSms)的集成 好记性不如烂笔头,记录一下集成阿里云短信平台的过程。 平台申请的过程略过,只讲代码有关的内容,首先是配置需要的依赖包: <!-- begin of aliyun sms --> <dependency> <groupId>com.aliyun</groupId> <artifactId>ali... 阅读详情

4.重构实例-消息发送-添加转换方法

由于这是一个长文,分成了好几章来介绍如何重构。

  1. 原始代码及准备
  2. 职责独立
  3. 去除static关键字
  4. 接口添加转换方法
  5. 方法合并
  6. 使用策略进行重构-Map方式
  7. 使用策略进行重构-枚举方式

经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。经过这两轮重构后,有没有什么设计是不合理的呢?再次回收代码中:

public class MessageSender {

  public void sendMessage(String msgType, MessageData notify) {
    MessageTypeEnum typeEnum = MessageTypeEnum.getEnumType(msgType);
    switch (typeEnum) {
        // 短信发送
      case SMS:
        sendSms(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // email的发送
      case EMAIL:
        sendMail(
            notify.getFunCode(), notify.getNotifyNumber(), notify.getTitle(), notify.getContent());
        break;
        // 微信的发送
      case WECHAT:
        sendWxMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 钉钉的消息发送
      case DINGDING:
        sendDingDingMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 企业钉钉的消息发送
      case WORKWECHAT:
        sendWorkWeChatMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 其他不做处理
      case OTHER:
        break;
      default:
        break;
    }
  }

  /**
   * 给一个邮箱,发送邮件
   *
   * @param funCode 功能类型编码
   * @param sendToMail 地址
   * @param subject 主题
   * @param content 内容
   * @return 返回发送结果
   */
  public boolean sendMail(String funCode, String sendToMail, String subject, String content) {
    EmailMsgData msgData = new EmailMsgData(sendToMail, subject, content);
    MessageSenderInf emailSender = new SmsSender();
    emailSender.sender(msgData);
    return true;
  }

  /**
   * 给单个手机号,发送短信
   *
   * @param funCode 功能类型编码
   * @param sendToMobileNos 接收的号码
   * @param smsContent 短信内容
   */
  public void sendSms(String funCode, String sendToMobileNos, String smsContent) {
    MsgData smsData = new MsgData(sendToMobileNos, smsContent);
    MessageSenderInf smsSender = new SmsSender();
    smsSender.sender(smsData);
  }

  /**
   * 给单个微信openID,发送模板消息(类似银行交易提醒通知)
   *
   * @param funCode 功能类型编码
   * @param toUserOpenId 发送的目标用户(微信openId)
   * @param context 内容
   */
  public void sendWxMsg(String funCode, String toUserOpenId, String context) {
    FunCodeMsgData weChatData = new FunCodeMsgData(toUserOpenId, context, funCode);
    MessageSenderInf weChatSender = new WeChatSender();
    weChatSender.sender(weChatData);
  }

  /**
   * 发送钉钉消息
   *
   * @param funCode 功能类型编码
   * @param toUserOpenId 接收的id
   * @param context 发送的内容
   */
  public void sendDingDingMsg(String funCode, String toUserOpenId, String context) {
    FunCodeMsgData dingDingData = new FunCodeMsgData(toUserOpenId, context, funCode);
    MessageSenderInf dingDingSender = new DingDingSender();
    dingDingSender.sender(dingDingData);
  }

  /**
   * 企业微信消息的发送
   *
   * @param funCode 功能类型编码
   * @param toUserOpenId 接收消息的id
   * @param context 发送的内容
   */
  public void sendWorkWeChatMsg(String funCode, String toUserOpenId, String context) {
    FunCodeMsgData dingDingData = new FunCodeMsgData(toUserOpenId, context, funCode);
    MessageSenderInf workWeChatSender = new DingDingSender();
    workWeChatSender.sender(dingDingData);
  }
}

通过对MessageSender类的观察,可以发现,这每个方法做的事情都是一样的,都是先将参数封装为目标所需的对象,再将参数传递给发送程序,既然如此
参数的封装也应该在每个渠道发送之前做,由于每个渠道的发送的消息不同,但它们都需要经过转换为目标对象,再才能进行发送。再来看看这个代码,每个
发送渠道的参数都传递了单独的参数。但参数都是一样的,将MessageData折开再发送,这是明显不合理的。

4.1 操作步骤

  1. 明确修改点。

  2. 修改MessageSender的单元测试。

  3. 修改MessageSender发送调用。

  4. 修改消息按类型发送消息的单元测试。

  5. 修改接口,增加转换方法。

  6. 对实现添加单元测试。

  7. 对原有发送渠道的类增加转换方法。

  8. 单元测试运行通过。

  9. 修改客户端的对于各渠道发送代码的调用。

  10. 运行单元测试以验证全部功能。

4.2 明确修改点。

a. 是MessageSender的参数不合理,统一修改为MessageData对象。
b. 每个接口都需要做消息的转换。再发送,针对这个消息转换方法来说,是需要放到公共的接口中去的。
明确这几点后,开始干吧。

4.3 修改MessageSender的单元测试

public class TestMockMessageSender {
......
  @Test
  @DisplayName("测试发送短信通知")
  public void testSmsSender() {
    MessageSender instance = new MessageSender();
    MessageData smsData = new MessageData();
    smsData.setNotifyNumber("13412345678");
    smsData.setContent("测试短信息的内容信息");
    instance.sendSms(smsData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @DisplayName("邮件发送邮件通知")
  public void testEmailSender() {
    MessageSender instance = new MessageSender();
    MessageData emailData = new MessageData();
    emailData.setNotifyNumber("134@163.com");
    emailData.setTitle("测试邮件通知");
    emailData.setContent("测试邮件的内容信息");
    instance.sendMail(emailData );
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @DisplayName("微信发送通知")
  public void testWechatSender() {
    MessageSender instance = new MessageSender();
    MessageData weChatata = new MessageData();
    weChatata.setFunCode("dataTest");
    weChatata.setNotifyNumber("131234567");
    weChatata.setContent("微信消息内容");
    instance.sendWxMsg(weChatata);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @DisplayName("钉钉发送通知")
  public void testDingDingSender() {
    MessageSender instance = new MessageSender();
    MessageData dingdingData = new MessageData();
    dingdingData.setFunCode("dataTest");
    dingdingData.setNotifyNumber("131234567");
    dingdingData.setContent("钉钉发送通知");
    instance.sendDingDingMsg(dingdingData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @DisplayName("微信企业发送通知")
  public void testWorkWechatSender() {
    MessageSender instance = new MessageSender();
    MessageData workWeChatData = new MessageData();
    workWeChatData.setFunCode("dataTest");
    workWeChatData.setNotifyNumber("1231231");
    workWeChatData.setContent("企业钉钉通知");
    instance.sendWorkWeChatMsg(workWeChatData);
    // 无异常即为成功
    assertTrue(true);
  }
}

4.4 修改MessageSender发送消息调用。

public class MessageSender {

  public void sendMessage(String msgType, MessageData notify) {
    MessageTypeEnum typeEnum = MessageTypeEnum.getEnumType(msgType);
    switch (typeEnum) {
        // 短信发送
      case SMS:
        sendSms(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // email的发送
      case EMAIL:
        sendMail(
            notify.getFunCode(), notify.getNotifyNumber(), notify.getTitle(), notify.getContent());
        break;
        // 微信的发送
      case WECHAT:
        sendWxMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 钉钉的消息发送
      case DINGDING:
        sendDingDingMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 企业钉钉的消息发送
      case WORKWECHAT:
        sendWorkWeChatMsg(notify.getFunCode(), notify.getNotifyNumber(), notify.getContent());
        break;
        // 其他不做处理
      case OTHER:
        break;
      default:
        break;
    }
  }

  /**
   * 给一个邮箱,发送邮件
   *
   * @param emailMsg email消息
   * @return 返回发送结果
   */
  public void sendMail(MessageData emailMsg) {
    EmailMsgData msgData =
        new EmailMsgData(emailMsg.getNotifyNumber(), emailMsg.getTitle(), emailMsg.getContent());
    MessageSenderInf emailSender = new SmsSender();
    emailSender.sender(msgData);
  }

  /**
   * 给单个手机号,发送短信
   *
   * @param smsMsg 短信消息
   */
  public void sendSms(MessageData smsMsg) {
    MsgData smsData = new MsgData(smsMsg.getNotifyNumber(), smsMsg.getContent());
    MessageSenderInf smsSender = new SmsSender();
    smsSender.sender(smsData);
  }

  /**
   * 给单个微信openID,发送模板消息(类似银行交易提醒通知)
   *
   * @param weChatMsg 微信消息
   */
  public void sendWxMsg(MessageData weChatMsg) {
    FunCodeMsgData weChatData =
        new FunCodeMsgData(
            weChatMsg.getNotifyNumber(), weChatMsg.getContent(), weChatMsg.getFunCode());
    MessageSenderInf weChatSender = new WeChatSender();
    weChatSender.sender(weChatData);
  }

  /**
   * 发送钉钉消息
   *
   * @param dingDingMsg 钉钉消息信息
   */
  public void sendDingDingMsg(MessageData dingDingMsg) {
    FunCodeMsgData dingDingData =
        new FunCodeMsgData(
            dingDingMsg.getNotifyNumber(), dingDingMsg.getContent(), dingDingMsg.getFunCode());
    MessageSenderInf dingDingSender = new DingDingSender();
    dingDingSender.sender(dingDingData);
  }

  /**
   * 企业微信消息的发送
   *
   * @param workWeChatMsg 企业微信消息
   */
  public void sendWorkWeChatMsg(MessageData workWeChatMsg) {
    FunCodeMsgData dingDingData =
        new FunCodeMsgData(
            workWeChatMsg.getNotifyNumber(),
            workWeChatMsg.getContent(),
            workWeChatMsg.getFunCode());
    MessageSenderInf workWeChatSender = new DingDingSender();
    workWeChatSender.sender(dingDingData);
  }
}

4.5 修改消息按类型发送消息的单元测试。

由于之前的单元测试中是以是否调用检查的,那还有没有其他的办法呢?这是我同样使用了mock技术,但是我对代码进行重过改进。
可以更方便的进行单元测试。
我使用按顺序排序来执行单元测试。由于jmockit使用ASM字节码修改技术将类的字节码进行了修改,必须放到后原生单元测试之后。否则单元测试将无法通过。
而在方法调用时使用了mock技术,当方法被调用,则抛出异常。在执行时后将异常进行检查。当做正常逻辑的一部分,则就可以进宪返回值的判断。是不是更
好呢?

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class TestMockMessageSender {

  private static final String ERROR_MSG = "invoke";

  @Test
  @Order(1)
  @DisplayName("测试发送短信通知")
  public void testSmsSender() {
    MessageSender instance = new MessageSender();
    MessageData smsData = new MessageData();
    smsData.setNotifyNumber("13412345678");
    smsData.setContent("测试短信息的内容信息");
    instance.sendSms(smsData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @Order(20)
  @DisplayName("邮件发送邮件通知")
  public void testEmailSender() {
    MessageSender instance = new MessageSender();
    MessageData emailData = new MessageData();
    emailData.setNotifyNumber("134@163.com");
    emailData.setTitle("测试邮件通知");
    emailData.setContent("测试邮件的内容信息");
    instance.sendMail(emailData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @Order(30)
  @DisplayName("微信发送通知")
  public void testWechatSender() {
    MessageSender instance = new MessageSender();
    MessageData weChatata = new MessageData();
    weChatata.setFunCode("dataTest");
    weChatata.setNotifyNumber("131234567");
    weChatata.setContent("微信消息内容");
    instance.sendWxMsg(weChatata);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @Order(40)
  @DisplayName("钉钉发送通知")
  public void testDingDingSender() {
    MessageSender instance = new MessageSender();
    MessageData dingdingData = new MessageData();
    dingdingData.setFunCode("dataTest");
    dingdingData.setNotifyNumber("131234567");
    dingdingData.setContent("钉钉发送通知");
    instance.sendDingDingMsg(dingdingData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @Order(50)
  @DisplayName("微信企业发送通知")
  public void testWorkWechatSender() {
    MessageSender instance = new MessageSender();
    MessageData workWeChatData = new MessageData();
    workWeChatData.setFunCode("dataTest");
    workWeChatData.setNotifyNumber("1231231");
    workWeChatData.setContent("企业钉钉通知");
    instance.sendWorkWeChatMsg(workWeChatData);
    // 无异常即为成功
    assertTrue(true);
  }

  @Test
  @Order(100)
  @DisplayName("测试发送短信mock")
  public void testSmsSenderMock() {
    new MockUp<SmsSender>(SmsSender.class) {
      @Mock
      void sender(MsgData msg) {
        throw new IllegalArgumentException(ERROR_MSG);
      }
    };
    MessageSender instance = new MessageSender();
    MessageData data = new MessageData();
    data.setFunCode("dataTest");
    data.setNotifyNumber("13412345678");
    data.setTitle("测试短信息通知");
    data.setStatus(0);
    data.setContent("测试短信息的内容信息..");

    Exception exception =
        assertThrows(
            IllegalArgumentException.class,
            () -> {
              instance.sendMessage(MessageTypeEnum.SMS.getMsgType(), data);
            });
    assertEquals(ERROR_MSG, exception.getMessage());
  }

  @Test
  @Order(110)
  @DisplayName("邮件发送邮件通知Mock")
  public void testEmailSenderMock() {
    new MockUp<EmailSender>(EmailSender.class) {
      @Mock
      void sender(MsgData msg) {
        throw new IllegalArgumentException(ERROR_MSG);
      }
    };
    MessageSender instance = new MessageSender();
    MessageData data = new MessageData();
    data.setFunCode("dataTest");
    data.setNotifyNumber("13412345678@163.com");
    data.setTitle("测试邮件息通知");
    data.setStatus(0);
    data.setContent("测试邮件的内容信息..");

    Exception exception =
        assertThrows(
            IllegalArgumentException.class,
            () -> {
              instance.sendMessage(MessageTypeEnum.EMAIL.getMsgType(), data);
            });
    assertEquals(ERROR_MSG, exception.getMessage());
  }

  @Test
  @Order(120)
  @DisplayName("微信发送通知mock")
  public void testWechatSenderMock() {
    new MockUp<WeChatSender>() {
      @Mock
      void sender(MsgData msg) {
        throw new IllegalArgumentException(ERROR_MSG);
      }
    };
    MessageSender instance = new MessageSender();

    MessageData data = new MessageData();
    data.setFunCode("dataTest");
    data.setNotifyNumber("1234567");
    data.setTitle("测试微信息通知");
    data.setStatus(0);
    data.setContent("测试微信的内容信息..");

    Exception exception =
        assertThrows(
            IllegalArgumentException.class,
            () -> {
              instance.sendMessage(MessageTypeEnum.WECHAT.getMsgType(), data);
            });
    assertEquals(ERROR_MSG, exception.getMessage());
  }

  @Test
  @Order(130)
  @DisplayName("钉钉发送通知mock")
  public void testDingDingSenderMock() {
    new MockUp<DingDingSender>() {
      @Mock
      void sender(MsgData msg) {
        throw new IllegalArgumentException(ERROR_MSG);
      }
    };

    MessageSender instance = new MessageSender();
    MessageData data = new MessageData();
    data.setFunCode("dataTest");
    data.setNotifyNumber("1234567");
    data.setTitle("测试钉钉通知");
    data.setStatus(0);
    data.setContent("测试钉钉的内容信息..");
    Exception exception =
        assertThrows(
            IllegalArgumentException.class,
            () -> {
              instance.sendMessage(MessageTypeEnum.DINGDING.getMsgType(), data);
            });
    assertEquals(ERROR_MSG, exception.getMessage());
  }

  @Mocked private WorkWeChatSender workWeChatSender;

  @Test
  @Order(140)
  @DisplayName("微信企业发送通知mock")
  public void testWorkWechatSenderMock() {
    new MockUp<WorkWeChatSender>() {
      @Mock
      void sender(MsgData msg) {
        throw new IllegalArgumentException(ERROR_MSG);
      }
    };

    MessageSender instance = new MessageSender();
    MessageData data = new MessageData();
    data.setFunCode("dataTest");
    data.setNotifyNumber("1234567");
    data.setTitle("测试企业微信通知");
    data.setStatus(0);
    data.setContent("测试企业微信的内容信息..");
    Exception exception =
        assertThrows(
            IllegalArgumentException.class,
            () -> {
              instance.sendMessage(MessageTypeEnum.WORKWECHAT.getMsgType(), data);
            });
    assertEquals(ERROR_MSG, exception.getMessage());
  }
}

4.6 修改接口,增加转换方法。

单元测试已经安全的修改完成,可以安全的进行重构。来将接口中增加转换方法吧吧。

public interface MessageSenderInf {

  /**
   * 消息发送
   *
   * @param msg 发送消息的内容
   */
  void sender(MsgData msg);

  /**
   * 消息转换方法
   *
   * @param msgData 发送的消息类型
   * @return 当前转换的类型
   */
  MsgData parse(MessageData msgData);
}

4.7 优先对实现添加单元测试。

sms消息转换的单元测试添加

public class TestSmsSender {
  ......
  @Test
  @DisplayName("测试短信的转换")
  public void testSmsParse() {
    SmsSender instance = new SmsSender();
    MessageData smsData = new MessageData();
    smsData.setNotifyNumber("13451913228");
    smsData.setContent("短信通知...");
    MsgData smsParse = instance.parse(smsData);
    // 检查发送结果
    assertEquals(smsData.getContent(), smsParse.getContext());
    assertEquals(smsData.getNotifyNumber(), smsParse.getToId());
  }
}

email的转换的单元测试添加

public class TestEmailSender {
......
  @Test
  @DisplayName("测试email的转换")
  public void testSmsParse() {
    EmailSender instance = new EmailSender();
    MessageData smsData = new MessageData();
    smsData.setNotifyNumber("134@163.com");
    smsData.setContent("邮件通知...");
    MsgData smsParse = instance.parse(smsData);
    // 检查发送结果
    assertEquals(smsData.getContent(), smsParse.getContext());
    assertEquals(smsData.getNotifyNumber(), smsParse.getToId());
  }
}

dingding发送的转换的单元测试添加

public class TestDingDingSender {
......
  @Test
  @DisplayName("钉钉的转换")
  public void testParseDingDing() {
    DingDingSender instance = new DingDingSender();
    MessageData dingMsg = new MessageData();
    dingMsg.setNotifyNumber("123464");
    dingMsg.setContent("钉钉的内容");
    MsgData dingParse = instance.parse(dingMsg);
    // 检查转换的结果
    assertEquals(dingMsg.getContent(), dingParse.getContext());
    assertEquals(dingMsg.getNotifyNumber(), dingParse.getToId());
  }
}

wechat的消息转换的单元测试添加

public class TestWeChatSender {
......
  @Test
  @DisplayName("测试微信的转换")
  public void weChatParse()
  {
    WeChatSender instance = new WeChatSender();
    MessageData wechatData = new MessageData();
    wechatData.setFunCode("dataTest");
    wechatData.setNotifyNumber("123456");
    wechatData.setContent("微信通知...");
    FunCodeMsgData weChatParse = (FunCodeMsgData) instance.parse(wechatData);
    assertEquals(wechatData.getFunCode(),weChatParse.getFunCode());
    assertEquals(wechatData.getNotifyNumber(),weChatParse.getToId());
    assertEquals(wechatData.getContent(),weChatParse.getContext());
  }
}

workwechat的消息转换的单元测试添加

public class TestWorkWeChatSender {
....
  @Test
  @DisplayName("测试工作微信消息的转换")
  public void workWeChatSender() {
    WorkWeChatSender instance = new WorkWeChatSender();

    MessageData workWechatData = new MessageData();
    workWechatData.setFunCode("dataTest");
    workWechatData.setNotifyNumber("123456");
    workWechatData.setContent("工作微信通知...");

    FunCodeMsgData workWeChatParse = (FunCodeMsgData) instance.parse(workWechatData);
    assertEquals(workWechatData.getNotifyNumber(), workWeChatParse.getToId());
    assertEquals(workWechatData.getFunCode(), workWeChatParse.getFunCode());
    assertEquals(workWechatData.getContent(), workWeChatParse.getContext());
  }
}

4.8 对原有发送渠道的类增加转换方法。

sms发送的消息转换

public class SmsSender implements MessageSenderInf {
......
  @Override
  public MsgData parse(MessageData msgData) {
    return new MsgData(msgData.getNotifyNumber(), msgData.getContent());
  }
}

email发送的消息转换

public class EmailSender implements MessageSenderInf {
......
  @Override
  public MsgData parse(MessageData emailMsg) {
    return new EmailMsgData(emailMsg.getNotifyNumber(), emailMsg.getTitle(), emailMsg.getContent());
  }
}

dingding发送消息的转换

public class DingDingSender implements MessageSenderInf {
......
  @Override
  public MsgData parse(MessageData dingDingMsg) {
    return new FunCodeMsgData(
        dingDingMsg.getNotifyNumber(), dingDingMsg.getContent(), dingDingMsg.getFunCode());
  }
}

wechat发送消息转换

public class WeChatSender implements MessageSenderInf {
......
  @Override
  public MsgData parse(MessageData weChatMsg) {
    return new FunCodeMsgData(
        weChatMsg.getNotifyNumber(), weChatMsg.getContent(), weChatMsg.getFunCode());
  }
}

workwechat发送消息转换

public class WorkWeChatSender implements MessageSenderInf {
......
  @Override
  public MsgData parse(MessageData workWeChatMsg) {
    return new FunCodeMsgData(
        workWeChatMsg.getNotifyNumber(), workWeChatMsg.getContent(), workWeChatMsg.getFunCode());
  }
}

4.9 单元测试运行通过。

运行单元测试以检查代码编写中是否存在问题。

4.10 修改客户端的对于各渠道发送代码的调用。


public class MessageSender {

  public void sendMessage(String msgType, MessageData notify) {
    MessageTypeEnum typeEnum = MessageTypeEnum.getEnumType(msgType);
    switch (typeEnum) {
        // 短信发送
      case SMS:
        sendSms(notify);
        break;
        // email的发送
      case EMAIL:
        sendMail(notify);
        break;
        // 微信的发送
      case WECHAT:
        sendWxMsg(notify);
        break;
        // 钉钉的消息发送
      case DINGDING:
        sendDingDingMsg(notify);
        break;
        // 企业钉钉的消息发送
      case WORKWECHAT:
        sendWorkWeChatMsg(notify);
        break;
        // 其他不做处理
      case OTHER:
        break;
      default:
        break;
    }
  }

  /**
   * 给一个邮箱,发送邮件
      *
   * @param emailMsg email消息
   * @return 返回发送结果
      */

    public void sendMail(MessageData emailMsg) {
    
    MessageSenderInf emailSender = new EmailSender();
    emailSender.sender(emailSender.parse(emailMsg));
  }

  /**
   * 给单个手机号,发送短信
      *
   * @param smsMsg 短信消息
      */

    public void sendSms(MessageData smsMsg) {
    
    MessageSenderInf smsSender = new SmsSender();
    smsSender.sender(smsSender.parse(smsMsg));
  }

  /**
   * 给单个微信openID,发送模板消息(类似银行交易提醒通知)
      *
   * @param weChatMsg 微信消息
      */

    public void sendWxMsg(MessageData weChatMsg) {
    
    MessageSenderInf weChatSender = new WeChatSender();
    weChatSender.sender(weChatSender.parse(weChatMsg));
  }

  /**
   * 发送钉钉消息
      *
   * @param dingDingMsg 钉钉消息信息
      */

    public void sendDingDingMsg(MessageData dingDingMsg) {
    
    MessageSenderInf dingDingSender = new DingDingSender();
    dingDingSender.sender(dingDingSender.parse(dingDingMsg));
  }

  /**
   * 企业微信消息的发送
      *
   * @param workWeChatMsg 企业微信消息
      */

    public void sendWorkWeChatMsg(MessageData workWeChatMsg) {
    
    MessageSenderInf workWeChatSender = new WorkWeChatSender();
    workWeChatSender.sender(workWeChatSender.parse(workWeChatMsg));
  }
}

4.11 运行单元测试以验证全部功能。

至此对于在接口中添加转换方法的重构结束。

Seurat版本兼容实战:从v5对象无缝降级到v4的完整指南 本文详细介绍了如何将Seurat v5对象无缝降级到v4版本的完整指南,重点解析了v5与v4在数据结构上的核心差异,并提供了实战转换代码和常见问题解决方案。通过对象转换和元数据检查,确保数据在版本降级过程中的完整性和一致性,帮助用户解决版本兼容性问题。 阅读详情

相关推荐

进制转换不止于做题:用Python三行代码重构ZZULIOJ 1141,并聊聊计算机中的‘数’

本文通过对比C语言和Python在ZZULIOJ 1141题中的进制转换实现,展示了Python的简洁与高效。深入探讨了进制转换的数学原理及其在计算机科学中的实际应用,帮助读者理解不同编程语言的设计哲学和适用场景。

weixin_30335353的博客 267

重构实例-消息发送-职责独立-2

2. 重构-策略模式-职责独立 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 现在来分析下代码的问题 先从入口MessageSender开始吧,这个类第一眼看上去,觉得很简单吧,就是按类型判断下,执行NotifySendUtils类中 的发送逻辑代码。这样子看这个类没有什么大的问题么,再说NotifySendUtils吧,它封装了各种发送渠道的调用方法,还做成了静态方

bug_null的博客 312

27、Erlang代码重构:提升代码质量与可维护性

本文深入探讨了Erlang代码重构的相关概念、场景及七种重构转换方法,通过聊天服务器示例展示了如何提升代码质量与可维护性。内容涵盖提取函数、合并表达式重复项、重命名变量与函数、重新排序参数、元组化参数等关键技术,并分析了重构工具RefactorErl在不同开发场景下的应用与挑战。

js777的博客 108

重构实例-消息发送-方法合并-5

5.重构实例-消息发送-方法合并 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。还为消息发送接口添加了转换方法。经过这几轮的修改,代码已经看起来整洁、 清晰了许多。那还有槽点吗? public class MessageSender { public void sendMessage(Stri

bug_null的博客 243

18、容器类与电影院案例研究编程指南

本文详细介绍了编程中常用的容器类,包括排序集合类、区间类、字符串类和符号类,并通过电影院业务管理的案例研究,展示了如何在实际场景中应用这些容器类。文章还涵盖了集合之间的转换方法以及代码重构的相关内容,旨在帮助开发者更好地管理和组织数据,提高代码质量和可维护性。

Python的专栏 60

2023携程面试题

Java NIO 的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。InnoDB 的锁粒度为行锁、MyISAM 的锁粒度为表锁、行锁需要对每一行进行加锁,所以锁的开销更大,但是能解决脏读和不可重复读的问题,相对来说也更容易发生死锁l 可恢复性上:由于 InnoDB 是有事务日志的,所以在产生由于数据库崩溃等条件后,可以根据日志文件进行恢复。

喜欢猪猪 2155

进程间的消息队列及msgtype的用法

Client.c #include #include #include #include #include #include #include #include #include extern int errno; #define ClientKey 1234 static int gs_nClientMsgid = -1; typedef struct st

烟花易冷 9211

别再傻傻分不清!5分钟搞懂倾斜摄影里‘地面分辨率’和‘模型精度’到底啥关系

本文深入解析倾斜摄影中‘地面分辨率’与‘模型精度’的关系,帮助读者快速理解两者的本质区别与内在关联。通过实战案例和公式计算,详细说明如何从航飞设计到精度验证全流程控制,避免常见认知误区,并针对不同应用场景提供精度需求建议。

weixin_33700350的博客 476

重构实例-消息发送-原始代码及准备-1

1. 重构-策略模式-原始代码及准备 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 1.1 原始代码 这是来自于我所经历的项目中一个消息发送的程序,调用者告诉发送程序:类型、接收者及消息的内容,发送程序会根据发送的类型调用不同的发送程序,将待发送的消息发送出去。 目前已知的发送渠道包括:短信、email、微信、钉钉、企业微信, 由于短信、email、微信、钉钉、企业

bug_null的博客 327

基于PLC的冲压件自动生产线电气系统设计【附数据】

考虑到生产线的高效运行和维护简便性,选择了三菱FX系列的可编程逻辑控制器(PLC)作为核心控制单元,该型号的PLC因其高可靠性和强大的功能集,在工业自动化领域有着广泛的应用。最后,在完成初步的软件开发后,进行了多轮次的模拟测试和现场调试,逐步修正了存在的问题,最终达到了预期的功能要求。例如,对于进料环节,选用了光电传感器以精确检测物料的位置;此外,为了适应不同尺寸的工件加工需求,还特别设计了一套可调节的夹具系统,不仅提高了生产线的灵活性,同时也降低了更换模具的成本。✅ 感恩科研路上每一位志同道合的伙伴!

lagougongzuoshi的博客 1291

RS-485调试踩坑实录:MAX13487数据回环问题排查与修复(附电路图)

本文深入解析了RS-485通信中MAX13487芯片的数据回环问题,提供了详细的排查过程和解决方案。通过分析芯片特性和自动换向机制,揭示了RO引脚配置不当是导致问题的关键原因,并给出硬件(添加上拉电阻)和软件(调整MCU配置)两种修复方案,附有优化设计建议和实际调试技巧。

play7的博客 1297

重构实例-消息发送-去除static关键字-3

3. 重构实例-消息发送-去除static关键字 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 现在来思考下NotifySendUtils中直接调用发送代码的做法,是否合理呢?或者说在我们原来的代码中,增加了一层调用,有必要吗?我觉得这个问题得分场景 来看,如果是一个大系统中的一部分,NotifySendUtils被几十甚至上百的文件引用,那么这样的改动是相当合理的,

bug_null的博客 262

Cortex-M异常处理深度解析:从HardFault到调试实战

在嵌入式开发中,Cortex-M系列处理器的异常处理机制是保障系统可靠性的核心。然而,面对HardFault、MemManage、BusFault等异常时,开发者往往陷入迷茫。本文结合SEGGER AN00016和Keil AN209两篇权威文档,深入剖析异常根源、寄存器解析及调试技巧,并通过代码实例演示如何快速定位问题。

汽车电子软件领域知识分享 2532

重构实例-消息发送-使用策略进行重构-Map方式-6

6 重构实例-消息发送-使用策略进行重构-Map方式 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 6.1 问题分析 经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。还为消息发送接口添加了转换方法,并对代码进行了方法的合并操作。 经过这几轮的修改,代码已经看起来整洁、清晰了许多。但是还存在一个问题,那就是每当要添加一个新的渠道的时候,就得改动Mess

bug_null的博客 221

Windows加域迁移避坑指南:Profwiz工具实战中的5个常见问题与解决方案

本文详细解析了使用Profwiz工具进行Windows加域迁移时的5个常见问题及解决方案,包括临时配置文件生成、密码策略冲突、SID冲突等。通过实战案例和优化技巧,帮助IT运维团队高效完成账户配置文件迁移,确保Active Directory环境下的数据完整性和权限无缝衔接。

q9r0s的博客 517

Power Switch与Tap Cell关系

tap cell可以选用一般类型的tap cell,无须secondary pg pin,因为此时switch cell的阱电位接到输入power net上了,switch cell可以正常上电,也可以给core内正常供电,tap cell的阱电位接switch cell输出的power,需要注意的是此时switch cell与core内其他cell的阱电位是不同的,所以为了避免drc问题,需要在switch上盖hard blockage或者keepout margin。2)自带阱偏置的switch。

m0_61544122的博客 2334

重构实例-消息发送-使用策略进行重构-枚举方式-7

7. 重构实例-消息发送-使用策略进行重构-枚举方式 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过上一次的重构我想你基本理解了使用map的策略模式,我们再来看使用策略模式的另一种实现list 7.1 重构步骤 这个还是规矩 检查单元测试。 使用枚举将类型与实例相绑定。 进行策略的实现。 执行单元测试。 7.2 检查单元测试 这个单元测试没有变化,可跳过 7.

bug_null的博客 209

2、机器人控制技术:阻抗/导纳控制与强化学习的融合

本文探讨了阻抗/导纳控制与强化学习在机器人控制中的融合应用。阻抗/导纳控制广泛应用于外骨骼和跟踪控制,通过改进方案提升建模误差下的鲁棒性;强化学习则为解决维度灾难、实现最优交互提供了有效途径,尤其在大输入空间、连续时间系统、冗余机器人及鲁棒控制中表现突出。结合近似器与合理奖励设计,强化学习可在无模型情况下实现高效控制。未来,两者融合有望推动更智能、更安全的机器人系统发展。

ice55的博客 299

5个gogoprotobuf代码重构技巧:提升Go项目代码质量与可维护性

gogoprotobuf是Go语言中高效的Protocol Buffers实现,通过合理的代码重构可以显著提升项目的性能和可维护性。本文将分享5个实用的gogoprotobuf代码重构技巧,帮助开发者优化Protobuf定义和生成代码,打造更健壮的Go应用。 ## 1. 使用自定义类型优化字段定义 在Protobuf定义中引入自定义类型可以提升代码的可读性和类型安全性。通过`gogoproto

gitblog_00611的博客 951

基于 STM32 的智能水表流量计设计与实现 —— 数据采集与远程传输

本文设计的基于 STM32 的智能水表流量计通过霍尔传感器实现流量采集,结合 STM32 的处理能力完成数据计算、存储与远程传输,具备计量精准、功耗低、可远程监控等特点。未来可优化方向:引入低功耗模式延长电池寿命,增加水质检测模块实现多参数监测,提升水务管理智能化水平。

weixin_42300449的博客 1027

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

技术业力与思想逆转:重构遗留系统的系统性思维与实践

在软件工程领域,技术债务是随着系统迭代和团队变动而逐渐累积的代码与架构问题,它会导致系统可维护性下降、开发效率降低。其核心原理在于代码耦合度高、缺乏清晰边界和自动化质量保障,使得修改成本激增。从技术价值看,有效管理技术债务能显著提升系统的可测试性、可扩展性和团队交付效率。常见的应用场景包括处理遗留系统、进行架构演进以及优化持续集成流程。本文聚焦于通过渐进式重构、依赖注入和防腐层等具体模式,结合表征测试与自动化门禁,实现从被动适应到主动设计的思维转变,从而系统性地清理技术业力,重建对代码库的控制力。

weixin_30521161的博客 440

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

【机房重构】——DataTable和泛型集合

引言    在机房重构还剩下上下机功能的时候突然听到这么一个消息——我们最好不要用DataTable来从D层返回,应该用泛型集合!当时没有特别在意这件事情,因为那时候的注意力都在设计模式的添加和应用上面,没有过多的考虑“泛型”这方面的知识,当我完成基本功能以后,这个想法有冒出来了,所以这次没有再次放过,而是找了一些相关资料来总结了一下,下面和大家共享一下我的总结:   DataTabel的弊端

Jack 架构师之路 1574

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

CAN协议解析的艺术:从原始字节到智能预警系统的数据重构

本文深入探讨CAN协议解析技术,从原始字节流解码到构建智能预警系统的完整流程。详细介绍了USB2CAN设备数据收发、位操作与多字段提取技术,以及基于Qt5的上位机模块化架构设计,实现高效的数据重构与实时预警功能。

night的博客 1006

2312llvm,09clang工具下

2312llvm,09clang工具下

个人进步之路 624

NewLife核心组件2026年3月版发布

新增 Benchmark 基准测试项目(net10.0),覆盖 IPacket、MemoryCache、TCP Echo、NetServer 等核心场景。:为网络库核心功能、UriInfo、PeerEndpointSelector、ApiHttpClient 等新增大量单元测试。:新增高性能 Span 二进制序列化器,支持零分配读写,性能全面优于传统方式。:简化线程池和长任务在日志里的名字,让应用启动时的日志更整齐。:优化 IPacket 切片逻辑,减少装箱,完善测试。

dotNET跨平台 54
上一篇: 重构实例-消息发送-去除static关键字-3
下一篇: 重构实例-消息发送-方法合并-5
null_null_bug
博客等级 码龄7年 72粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值