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

Go语言使用钉钉机器人推送消息 Go语言使用钉钉机器人推送消息 学习了Go语言后,打算利用最近比较空一点,写一个前端部署工具,不需要每次都复制粘贴的麻烦,我们希望再部署开始之前和部署结束后推送钉钉消息 创建一个钉钉机器人 这个比较简单 添加完后会给你一个webhook就是我们发送消息的地址 推送消息 show code! func SendDingMsg(msg string) { //请求地址模板 webHook :=... 阅读详情

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

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

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

现在来分析下代码的问题

先从入口MessageSender开始吧,这个类第一眼看上去,觉得很简单吧,就是按类型判断下,执行NotifySendUtils类中
的发送逻辑代码。这样子看这个类没有什么大的问题么,再说NotifySendUtils吧,它封装了各种发送渠道的调用方法,还做成了静态方法。这里明显就
存在问题了, 首先从职责上来说,NotifySendUtils类承担了过多的职责,它封装了发送短信,还封装了发送邮件,以及其他几种渠道的发送代码,
职责过多。再者NotifySendUtils的方法设计成静态方法我觉得也是存在问题的,因为在现实情况中它是有依赖的,它依赖于各种消息发送渠道的物理调用。
这样子是不适合做静态方法的,要做静态方法,首先的原则就是不要有依赖,比如工具类等。

针对这个职责过多怎么重构呢?
通常我的做法将发送渠道的相关代码都迁移到独立类中。这样每个发送渠道都可以单独管理,每次修改代码,也只会影响到修改的,不会影响到其他的代
码,但如果都在一个类中,当修改代码时,不小心误删了其他的代码,所造成的问题,很可能是难以察觉的。如果是一个团队维护的代码,那所造成的问
题将进一步放大,问题定位的成本更高。

2.1 迁移方法

将原本NotifySendUtils的5个方法进行复制

2.1.1 将sendSms复制至SmsSender类中
public class SmsSender {

  /**
   * 给单个手机号,发送短信
   *
   * @param funCode 功能类型编码
   * @param sendToMobileNos 接收的号码
   * @param smsContent 短信内容
   */
  public static void sendSms(String funCode, String sendToMobileNos, String smsContent) {
    System.out.println("短信的发送开始.....");
    System.out.println(
            "短信发送: " + ",sendToMobileNos:" + sendToMobileNos + ",smsContent:" + smsContent);
    System.out.println("短信的发送结束.....");
  }
}
2.1.2 将sendMail复制至EmailSender类中
public class EmailSender {

  /**
   * 给一个邮箱,发送邮件
   *
   * @param funCode 功能类型编码
   * @param sendToMail 地址
   * @param subject 主题
   * @param content 内容
   * @return 返回发送结果
   */
  public static boolean sendMail(
          String funCode, String sendToMail, String subject, String content) {
    System.out.println("邮件的发送开始.....");
    System.out.println(
            "邮件发送: " + ",sendToMail:" + sendToMail + ",subject:" + subject + ",content:" + content);
    System.out.println("短信的发送结束.....");
    return true;
  }
}
2.1.3 将sendWxMsg复制至WeChatSender类中
public class WeChatSender {

    /**
     * 给单个微信openID,发送模板消息(类似银行交易提醒通知)
     *
     * @param funCode 功能类型编码
     * @param toUserOpenId 发送的目标用户(微信openId)
     * @param context 内容
     */
    public static void sendWxMsg(String funCode, String toUserOpenId, String context) {
        System.out.println("微信消息发送开始.....");
        System.out.println(
                "微信消息:funCode" + funCode + ",toUserOpenId:" + toUserOpenId + ",context:" + context);
        System.out.println("微信消息发送结束.....");
    }
}
2.1.4 将sendDingDingMsg复制至DingDingSender类中
public class DingDingSender {

  /**
   * 发送钉钉消息
   *
   * @param funCode 功能类型编码
   * @param toUserOpenId 接收的id
   * @param context 发送的内容
   */
  public static void sendDingDingMsg(String funCode, String toUserOpenId, String context) {
    System.out.println("钉钉消息发送开始.....");
    System.out.println(
        "钉钉消息:funCode" + funCode + ",toUserOpenId:" + toUserOpenId + ",tplData:" + context);
    System.out.println("钉钉消息发送结束.....");
  }
}
2.1.5 将sendWorkWeChatMsg复制至WorkWeChatSender类中
public class WorkWeChatSender {

  /**
   * 企业微信消息的发送
   *
   * @param funCode 功能类型编码
   * @param toUserOpenId 接收消息的id
   * @param context 发送的内容
   */
  public static void sendWorkWeChatMsg(String funCode, String toUserOpenId, String context) {
    System.out.println("企业微信消息发送开始.....");
    System.out.println(
        "企业微信消息:funCode" + funCode + ",toUserOpenId:" + toUserOpenId + ",tplData:" + context);
    System.out.println("企业微信消息发送结束.....");
  }
}

至此,第一步将代码复制到各个类的工作完成了。是不是觉得很不可思议,第一步居然是拷贝代码,而且还是直接拷贝一样的代码,难道不能直接把代码迁移到
目标类中吗?一般是不建议这么做的,有以下原因:

  1. 直接迁移代码,必然导致所依赖的所有类都编译报错,而一旦依赖此类文件的特别多,必然导致一改改一片的情况。
  2. 在没有将旧代码重构完成之前就修改原来的代码,可能会导致程序客户端被反复的修改。
  3. 由于自己提交的文件还可能被其他人调用,如果将文件修改到一半就提交了,其他人的引用必须报错,也会影响其他人的工作。

基于以上三点考量,正确的修改姿势:

  1. 将原先的代码复制一份出来,用于做重构的代码基线。
  2. 将单元测试同样的也拷贝到对应的文件中。
  3. 重构一点代码,运行一遍单元测试。确保修改是一点一点进行的,不要步幅过大。
  4. 重构完成后,考量原先的代码的处理,自己给出修改方案。并加以实施。
  5. 运行单元测试。确保代码还能正确的运行。

2.2 老规矩,开始重构之前先写单元测试.

sms的单元测试

public class TestSmsSender {
  @Test
  @DisplayName("测试短信发送")
  public void testSmsSender() {
    SmsSender.sendSms("datTest", "1341231241", "this is test");
    // 无异常即为成功
    assertTrue(true);
  }
}

email的单元测试

public class TestEmailSender {

  @Test
  @DisplayName("邮件发送")
  public void testSenderEmail() {
    EmailSender.sendMail("data", "123@163.com", "this is test", "context");
    // 无异常即为成功
    assertTrue(true);
  }
}

dingding的单元测试

public class TestDingDingSender {

  @Test
  @DisplayName("发送钉钉测试")
  public void senderDingDing() {
    DingDingSender.sendDingDingMsg("test", "1231", "data test");
    // 无异常即为成功
    assertTrue(true);
  }
}

wechat的单元测试

public class TestWeChatSender {

  @Test
  @DisplayName("测试微信发送消息")
  public void senderWeChat() {
    WeChatSender.sendWxMsg("dataFun", "1231", "this is test");
    // 无异常即为成功
    assertTrue(true);
  }
}

workWechat的单元测试

public class TestWorkWeChatSender {

  @Test
  @DisplayName("测试企业微信")
  public void senderWorkWeChat() {
    WorkWeChatSender.sendWorkWeChatMsg("dataFun", "1231", "this is test Count");
    // 无异常即为成功
    assertTrue(true);
  }
}

2.3 首先修改单元测试,然后再去掉static关键字。

单元测试修改

public class TestSmsSender {
  @Test
  @DisplayName("测试短信发送")
  public void testSmsSender() {
    SmsSender instance = new SmsSender();
    instance.sendSms("datTest", "1341231241", "this is test");
    // 无异常即为成功
    assertTrue(true);
  }
}

类的修改

public class SmsSender {

  /**
   * 给单个手机号,发送短信
   *
   * @param funCode 功能类型编码
   * @param sendToMobileNos 接收的号码
   * @param smsContent 短信内容
   */
  public void sendSms(String funCode, String sendToMobileNos, String smsContent) {
    System.out.println("短信的发送开始.....");
    System.out.println(
        "短信发送: " + ",sendToMobileNos:" + sendToMobileNos + ",smsContent:" + smsContent);
    System.out.println("短信的发送结束.....");
  }
}

其他类与此类似修改掉单元测试。再去除static关键字

2.4 共性抽取。

这几个类他们都是在做发消息,所不同的是发送渠道。所有的操作都是围饶着发消息而进行的,而不同点在于不同的发送渠道所需参数有所不同。针对这一类
情况,我会采用抽取接口,可能有人会说了,使用抽象类也可以啊!是的没错,采用抽象类也可以,但我一般不推荐使用抽象类,抽象类我一搬推荐在模板这
一类方法中,逻辑固定,子类只重写必须的方法。在这一类受限的场景中,抽象类才真正的发挥作用。而在java中采用的又是单根继承,只能继承一个父类,
这样就可能导致继承的层级非常的深。接口在这方面就没有限制,一个类可以实现多个接口,这样就可以任意组合不同接口,为程序提供了更大的灵活性。

到了该抽取接口的时候了,首先我们定义一个发送消息的接口MessageSenderInf,参数为所有渠道共用的参数。

public interface MessageSenderInf {

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

消息参数基础类

public class MsgData {

  /** 接收的id */
  private String toId;

  /** 发送的消息的内容 */
  private String context;

  public MsgData(String toId, String context) {
    this.toId = toId;
    this.context = context;
  }

  public String getToId() {
    return toId;
  }

  public void setToId(String toId) {
    this.toId = toId;
  }

  public String getContext() {
    return context;
  }

  public void setContext(String context) {
    this.context = context;
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("MsgData{");
    sb.append("toId='").append(toId).append('\'');
    sb.append(", context='").append(context).append('\'');
    sb.append('}');
    return sb.toString();
  }
}

消息带功能编码的类,由于功能编码非所有渠道所共有,一般建议拆开,但如果就一个参数合到一起,也是可以接受的,但我一般都是拆开,我不想这一两个
参数去污染公共类,公共是所有都有的,非所有都有的,那就是需要额外定义。这样不会因为一个参数而不论不类。而后期再做修改的时候,也更加的容易,
还有一个原因就,坏习惯会传染,如果自己就打破了这个类只封装公有的原则,其他的人也肯定会跟着效仿。

消息扩展类

public class FunCodeMsgData extends MsgData {

  /** 功能类型编码 */
  private String funCode;

  public FunCodeMsgData(String toId, String context, String funCode) {
    super(toId, context);
    this.funCode = funCode;
  }

  public String getFunCode() {
    return funCode;
  }

  public void setFunCode(String funCode) {
    this.funCode = funCode;
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("FunCodeMsgData{");
    sb.append("funCode='").append(funCode).append('\'');
    sb.append('}');
    sb.append(super.toString());
    return sb.toString();
  }
}

先对消息的发送的单元测试进行改造,再来修改原代码。
sms通知的单元测试的修改

public class TestSmsSender {
  @Test
  @DisplayName("测试短信发送")
  public void testSmsSender() {
    SmsSender instance = new SmsSender();
    MsgData msgData = new MsgData("1341345678", "this is test");
    instance.sender(msgData);
    // 无异常即为成功
    assertTrue(true);
  }
}

sms发送实现的修改

public class SmsSender implements MessageSenderInf {

  /**
   * 给单个手机号,发送短信
   *
   * @param msg 发送消息的内容
   */
  @Override
  public void sender(MsgData msg) {
    System.out.println("短信的发送开始.....");
    System.out.println(
        "短信发送: " + ",sendToMobileNos:" + msg.getToId() + ",smsContent:" + msg.getContext());
    System.out.println("短信的发送结束.....");
  }
}

email的通知的单元测试的修改

在进行修改的时候发现,对于email是存在主题的,这个需要由发送通知时进行设置,所以增加一个email的消息的类

public class EmailMsgData extends MsgData {

  /** 主题 */
  private String subject;

  public EmailMsgData(String toId,  String subject,String context) {
    super(toId, context);
    this.subject = subject;
  }

  public String getSubject() {
    return subject;
  }

  public void setSubject(String subject) {
    this.subject = subject;
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder("EmailMsgData{");
    sb.append("subject='").append(subject).append('\'');
    sb.append('}');
    sb.append(super.toString());
    return sb.toString();
  }
}
public class TestEmailSender {

  @Test
  @DisplayName("邮件发送")
  public void testSenderEmail() {
    EmailSender instance = new EmailSender();
    MsgData msg = new MsgData("123@163.com", "this context");
    instance.sender(msg);
    // 无异常即为成功
    assertTrue(true);
  }
}

email的发送实现的修改

public class EmailSender implements MessageSenderInf {

  /**
   * 给一个邮箱,发送邮件
   *
   * @param msg 发送的消息
   */
  @Override
  public void sender(MsgData msg) {
    System.out.println("邮件的发送开始.....");
    System.out.println(
        "邮件发送: "
            + ",sendToMail:"
            + msg.getToId()
            + ",subject: notify, content:"
            + msg.getContext());
    System.out.println("短信的发送结束.....");
  }
}

dingding的单元测试的修改

public class TestDingDingSender {

  @Test
  @DisplayName("发送钉钉测试")
  public void senderDingDing() {
    DingDingSender instance = new DingDingSender();
    FunCodeMsgData funCodeMsgData = new FunCodeMsgData("12312", "ding ding msg test", "funcode");
    instance.sender(funCodeMsgData);
    // 无异常即为成功
    assertTrue(true);
  }
}

dingding的实现的修改

public class DingDingSender implements MessageSenderInf {

  /**
   * 发送钉钉消息
   *
   * @param msg 消息信息
   */
  @Override
  public void sender(MsgData msg) {
    System.out.println("钉钉消息发送开始.....");
    FunCodeMsgData codeMsgData = (FunCodeMsgData) msg;
    System.out.println(
        "钉钉消息:funCode"
            + codeMsgData.getFunCode()
            + ",toUserOpenId:"
            + codeMsgData.getToId()
            + ",tplData:"
            + codeMsgData.getContext());
    System.out.println("钉钉消息发送结束.....");
  }
}

wechat的单元测试修改

public class TestWeChatSender {

  @Test
  @DisplayName("测试微信发送消息")
  public void senderWeChat() {
    WeChatSender instance = new WeChatSender();
    FunCodeMsgData funCodeMsg = new FunCodeMsgData("1231231", "this is test", "datafun");
    instance.sender(funCodeMsg);
    // 无异常即为成功
    assertTrue(true);
  }
}

wechat的单元测试修改

public class TestWeChatSender {

  @Test
  @DisplayName("测试微信发送消息")
  public void senderWeChat() {
    WeChatSender instance = new WeChatSender();
    FunCodeMsgData funCodeMsg = new FunCodeMsgData("1231231", "this is test", "datafun");
    instance.sender(funCodeMsg);
    // 无异常即为成功
    assertTrue(true);
  }
}

workwechat的单元测试修改

public class TestWorkWeChatSender {

  @Test
  @DisplayName("测试企业微信")
  public void senderWorkWeChat() {
    WorkWeChatSender instance = new WorkWeChatSender();
    FunCodeMsgData codeMsgData = new FunCodeMsgData("12312", "this is test", "datafun");
    instance.sender(codeMsgData);
    // 无异常即为成功
    assertTrue(true);
  }
}

workwechat的发送实现的修改

public class WorkWeChatSender implements MessageSenderInf {

  /**
   * 企业微信消息的发送
   *
   * @param msgData 消息内容
   */
  @Override
  public void sender(MsgData msgData) {
    System.out.println("企业微信消息发送开始.....");
    FunCodeMsgData funCodeMsg = (FunCodeMsgData) msgData;
    System.out.println(
        "企业微信消息:funCode"
            + funCodeMsg.getFunCode()
            + ",toUserOpenId:"
            + funCodeMsg.getToId()
            + ",context:"
            + funCodeMsg.getContext());
    System.out.println("企业微信消息发送结束.....");
  }
}

经过此所有的单元测试与实现都已经修改完成。

2.5 修改客户端调用

针对各种渠道的调用测试进行修改,重构前必须确保有单元测试,在之前各发送渠道的单元测试已经存在,便可直接重构。

public class NotifySendUtils {
  /**
   * 给一个邮箱,发送邮件
   *
   * @param funCode 功能类型编码
   * @param sendToMail 地址
   * @param subject 主题
   * @param content 内容
   * @return 返回发送结果
   */
  public static 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 static 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 static 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 static 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 static void sendWorkWeChatMsg(String funCode, String toUserOpenId, String context) {
    FunCodeMsgData dingDingData = new FunCodeMsgData(toUserOpenId, context, funCode);
    MessageSenderInf workWeChatSender = new DingDingSender();
    workWeChatSender.sender(dingDingData);
  }
}

2.6 运行单元测试。

运行单元测试确保修改后的代码都可以成功的运行。

2.7 关于我重构的一些方式及方法。

这里我重构了发送的代码,将原来的发送点,变成了发送的客户端。这样的改动是否合理呢? 我觉得是有必须,重构我一直遵循的一个原则就是小步快走。
而不是一步到位,一步到位固然很爽,但是我们在重构的时候,经常涉及到的文件可能是很多个,几十,有时甚至上百个,而且改动的周期可能会很长。如果
我们改动不能做到每步都可测试,那么最终的结果出现意外的情况必然很多,意外情况将导致更长的改动周期。令重构进行的相当不顺,而改用小步快走,每
改动一步,都确保是可以测试的,可执行的,那么最终的结果肯定也是可以执行的。这样的改动周期也不会比原来一步到位时间的长,由于我们每步都做到了可测试
出现意义情况的几率将大大的降低,由于代码随时都是可以运行的,对他人造成的影响也更少。所以我一般采用的的是小步快走的策略。

优化函数构成:用单一职责原则重构业务代码 函数构成(Composing Methods)是面向对象与函数式编程中提升代码可读性、可测性与可维护性的核心实践,其本质是依据单一职责原则(SRP)对逻辑进行语义化拆分,使每个函数仅响应一个变化原因。它并非简单切分代码,而是通过提取方法、内联临时变量、引入参数对象等模式,消除隐性耦合、明确输入输出边界,并支撑链式调用、策略模式与函数式组合等高阶复用。该技术广泛应用于电商订单处理、支付流程、用户注册等典型业务场景,尤其适合Java/Python等主流语言的后端开发团队落地。本文聚焦真实工程痛点,提供可量化的重 阅读详情

相关推荐

使用DDD(领域驱动设计)重构支付系统

领域驱动设计(DDD)和微服务架构是两种在架构设计领域广泛应用的方法。它们都旨在通过从业务视角分离应用系统的复杂度来提高系统响应力。

呱牛 Just do IT 1271

java 通过API调用钉钉机器人通知

java 通过API调用钉钉机器人通知

Chioce的博客 2639

别再只会用状态机了!LabVIEW项目实战:用QMH(队列消息处理器)重构你的数据采集程序

本文详细介绍了如何将LabVIEW数据采集程序从状态机架构升级为更高效的队列消息处理器(QMH)模式。通过分析状态机的局限性,展示QMH在界面响应、模块化和并发处理方面的优势,并提供从状态机到QMH的重构步骤和高级优化技巧,帮助开发者提升程序性能和可维护性。

weixin_30680385的博客 946

钉钉 php实现发送通知,Go语言实现钉钉发送通知

具体代码如下所示:package mainimport ("bufio""io""fmt""io/ioutil""os/exec""net/http""os""strings")func GetKey() (timestamp string ,sign string, err error){cmd := exec.Command("/bin/python", "/application/scrip...

weixin_36389335的博客 284

【CubeMX】STM32G474 HRTIM 互补PWM与死区时间配置实战

本文详细介绍了如何使用STM32CubeMX配置STM32G474的高分辨率定时器HRTIM生成互补PWM波形并精确设置死区时间。通过实战步骤讲解时钟配置、死区计算与高级功能,帮助工程师在电机驱动和电源应用中实现精准控制,避免上下桥臂直通风险。

grpc6streamer的博客 724

ScanNet数据集下载全攻略:从申请到解析的保姆级教程(含常见问题解决)

本文提供了ScanNet数据集从申请授权到下载、解析的完整实战指南。针对这个大规模室内RGB-D数据集,详细介绍了官方申请流程、优化下载策略、数据验证方法,并重点解决了深度图解析等常见问题,帮助三维视觉研究者高效获取和使用这一宝贵资源。

5f4d3s2a1q的博客 617

利用钉钉机器人发送告警信息

现在越来越多的人开始使用钉钉,对于运维告警来说,除了传统的邮件告警之外,短信告警、企业微信告警、钉钉机器人告警等也是首选考虑。这里介绍如果利用python+钉钉机器人 实现告警信息发送。 首先新增一个组专门用来接受告警信息,在组设置中看到组机器人Group robot,如下图: ...

aecuhty88306453的博客 483

华为P812E光猫补全shell配置PON口模式

终于看到华为企业级的带2.5电口P812E横空出世了,相信很多发烧友也已经将此收入昂中。相信体验的同时,遇到的第一件事情就是配置PON口模式的问题,本文将带发烧基友解锁模式。

GUAIYU的博客 5726

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

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

bug_null的博客 327

ComfyUI中一个超好用的变量管理类节点-KJNodes

在AI绘图中,ComfyUI的热度开始慢慢起来一些,但是这个软件在使用的过程中,需要很多连线,仅仅一个最简单的动画生成,就需要连接这么多线条,而且有些线会飞的很远,看起来就很不美观,尤其是一些复杂工作流,连接到最后自己可能已经分不太清楚到底连接好了没有。今天在研究C站的大佬们的工作流的时候,发现一个有意思的工作流,看起来大概是这种感觉:干净整洁。他用到了KJNodes这么个节点来管理变量,git上星标也不算很多,所以我想很多朋友可能还不知道,所以这里简单介绍下用法。

聚梦小课堂 7520

Unity URP项目里Post Processing死活没效果?别急,这5个坑我帮你踩过了

本文详细解析了Unity URP项目中Post Processing效果不显示的5个常见问题及解决方案,包括管线配置、Volume设置、摄像机选项、Layer冲突和Shader兼容性。通过专业排查步骤和实用代码片段,帮助开发者快速定位并修复后处理效果失效问题,提升项目开发效率。

weixin_28693309的博客 233

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

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

bug_null的博客 262

scGPT学习资料汇总 - 单细胞多组学基础模型

scGPT(single-cell Generative Pre-trained Transformer)是一个针对单细胞多组学数据的基础模型,由多伦多大学Wang Bo实验室开发。该模型通过在超过3300万个细胞上进行生成式预训练,捕捉了基因和细胞之间的复杂关系,为多种下游任务提供了强大的基础。scGPT为单细胞分析提供了强大的基础模型和丰富的资源。通过本文汇总的学习材料,读者可以快速掌握scGPT的使用,并将其应用到自己的研究中。

2401_87189860的博客 838

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

4.重构实例-消息发送-添加转换方法 由于这是一个长文,分成了好几章来介绍如何重构。 原始代码及准备 职责独立 去除static关键字 接口添加转换方法 方法合并 使用策略进行重构-Map方式 使用策略进行重构-枚举方式 经过前两轮的重构之后,已经提取了抽象接口,并将其static去掉。经过这两轮重构后,有没有什么设计是不合理的呢?再次回收代码中: public class MessageSender { public void sendMessage(String msgType, Messag

bug_null的博客 307

NVIDIA DRIVE SDK学习(二)——NvMedia

可以通过使用NvSciBuf API通过NvMedia Tensor属性分配NvSciBuf来创建NvMedia张量。由于NvSciBuf API有助于NvMedia和NVIDIA®CUDA®之间的数据共享,这使得分配的张量可以在NvSciBuf API允许的情况下重复使用。它支持图像聚合操作。NvSciSync组件使得NvMedia组件可以与其他组件保持同步,比如CUDA组件、基于NvSciSync的组件等。立体视差模式:在这种模式下,该模块通过左图像和右图像来产生立体视差,从而进行物体深度测量。

weixin_39592381的博客 3044

【深度学习时间序列预测案例】零基础入门经典深度学习时间序列预测项目实战(附代码+数据集+原理介绍)

本专栏整理了《深度学习时间序列预测案例》,内包含了各种不同的基于深度学习模型的时间序列预测方法,例如LSTM、GRU、CNN(一维卷积、二维卷积)、LSTM-CNN、BiLSTM、Self-Attention、LSTM-Attention、Transformer等经典模型,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。

优快云 精品推荐 4万+

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

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

bug_null的博客 221

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

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

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

bug_null的博客 243

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

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

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

bug_null的博客 209

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

从400行到30个文件:基于单一职责原则的Python服务模块化重构实践

在软件工程中,模块化是提升代码可维护性、可测试性和团队协作效率的核心实践。其原理在于遵循单一职责原则,将复杂系统拆分为高内聚、低耦合的独立单元,从而降低认知负荷和变更风险。这一技术的价值在于,它能将代码从“仅能运行”的状态,系统性地升级为易于理解、测试和维护的工程化资产。典型的应用场景包括处理遗留的“巨石应用”、构建需要长期迭代的业务系统,以及需要多人协作的中大型项目。本文以一次真实的Python服务重构为例,详细阐述了如何将一个近400行的风控模块,通过分层架构和依赖注入,拆分为30多个职责清晰的独立文件

weixin_30843121的博客 337

唯品会: 高吞吐消息网关的探索与思考

唯品会是一家立足于“全球精选,正品特卖”的电商网站,拥有4亿注册会员,日活约2千万会员。随着会员数量的增多,公司业务部门的飞速发展,和用户的沟通变得日益重要。沿用至今的消息网关,面对多变的业务和爆发式增长的消息面前,显得力不从心,多次大促出现性能瓶颈,急需重构来跟上公司业务发展的需要。

猪猪 1014

高吞吐消息网关的探索与思考

唯品会是一家立足于“全球精选,正品特卖”的电商网站,拥有4亿注册会员,日活约2千万会员。随着会员数量的增多,公司业务部门的飞速发展,和用户的沟通变得日益重要。沿用至今的消息网关,面对多变的业务和爆发式增长的消息面前,显得力不从心,多次大促出现性能瓶颈,急需重构来跟上公司业务发展的需要。唯品会消息网关的架构定位在本次重构中,将原来耦合在一起的消息发送渠道,被拆分成逻辑消息网关和物理发送渠道。逻辑消息...

imgxr的博客 1863

软件工程 5 大核心设计原理实战:从模块独立性到启发规则,附 3 个重构案例

本文深入解析软件工程五大核心设计原理(模块化、抽象、逐步求精、信息隐藏和模块独立性),并通过三个实战重构案例展示如何将这些理论应用于实际开发。内容涵盖电商系统、微服务API网关等典型场景,帮助开发者提升代码质量与可维护性,适合需要系统学习软件设计原理的工程师。

weixin_34185512的博客 318

代码重构艺术:如何用Python实现高内聚低耦合设计

当你在Python中实践高内聚低耦合设计时,记住这个黄金法则:每个模块应该只做好一件事,并且通过清晰的接口与外界对话。

m0_75042480的博客 624

windows 网络驱动开发_在线文档的网络层开发思考职责驱动设计

最近在负责通用网络层的设计和开发,会记录该过程中的一些思考,本文主要介绍职责驱动设计,以及它在网络层设计中的一些思考。之前有整理过《在线文档的网络层设计思考》一文,其中有较完整地介绍了网络层的一些职责,包括:校验数据合法性本地数据准确的提交给后台:包括有序递交和按序升版协同数据正确处理后分发给数据层:包括本地未递交数据与服务端协同数据的冲突处理和协同数据的按序应用在最初的想法中,我认为的...

weixin_39640911的博客 276
上一篇: 重构实例-消息发送-原始代码及准备-1
下一篇: 重构实例-消息发送-去除static关键字-3
null_null_bug
博客等级 码龄7年 72粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值